Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a build command and small fixes/changes to other parts of the Bot #36

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions bot/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import org.apache.tools.ant.filters.ReplaceTokens

plugins {
// id 'com.sedmelluq.jdaction' version '1.0.2' //warning: fails horribly on gradle 4.8+
}
Expand Down Expand Up @@ -49,6 +51,48 @@ dependencies {
testCompile 'junit:junit:4.12'
}

task getBotVersionInfo(type: Exec) {
commandLine 'git', 'log', '-1', '--format=[%ci]%n%H%n%s'

if (System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')) {
commandLine = ['cmd', '/c'] + commandLine
}

//store the output instead of printing to the console:
standardOutput = new ByteArrayOutputStream()

doLast {
tasks.versionSourcesForRelease.configure {
from (sourceSets.main.allJava) {
include '**/BotVersion.java'
filter(ReplaceTokens, tokens: [
VERSION: standardOutput.toString().trim().replace("\n", "\\n").replace("\"", "\\\""),
BUILD: buildNumber
])
}
}
}
}

task versionSourcesForRelease(type: Copy) {
dependsOn getBotVersionInfo
into 'build/filteredSrc'

includeEmptyDirs = false
}

task generateJavaSources(type: SourceTask, dependsOn: versionSourcesForRelease) {
def javaSources = sourceSets.main.allJava.filter {
it.name != 'BotVersion.java'
}
source = javaSources + versionSourcesForRelease.destinationDir
}

compileJava {
dependsOn generateJavaSources
source = generateJavaSources.source
}

run {
systemProperties System.properties
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.almightyalpaca.discord.jdabutler;

public class BotVersion
{
public static final String BUILD = "@BUILD@";
public static final String GIT_INFO = "@VERSION@";

private static final String[] GIT_LINES = GIT_INFO.split("\n");

public static final String GIT_DATE = GIT_LINES.length == 1 ? "" : GIT_LINES[0];
public static final String GIT_HASH = GIT_LINES.length == 1 ? "" : GIT_LINES[1];
public static final String GIT_MSG = GIT_LINES.length == 1 ? "" : GIT_LINES[2];

public static final String FULL_VERSION = String.format("Build: %s\n\nGit:\n%s", BUILD, GIT_INFO);
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public Dispatcher()
this.registerCommand(new AnnouncementCommand());
this.registerCommand(new SoftbanCommand());
this.registerCommand(new SlowmodeCommand());
this.registerCommand(new BuildCommand());
this.registerCommand(new UpdateCommand());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.almightyalpaca.discord.jdabutler.commands.commands;

import com.almightyalpaca.discord.jdabutler.Bot;
import com.almightyalpaca.discord.jdabutler.BotVersion;
import com.almightyalpaca.discord.jdabutler.commands.Command;
import net.dv8tion.jda.core.entities.Message;
import net.dv8tion.jda.core.entities.TextChannel;
import net.dv8tion.jda.core.entities.User;
import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent;

public class BuildCommand extends Command
{
@Override
public void dispatch(User sender, TextChannel channel, Message message, String content, GuildMessageReceivedEvent event)
{
if(!Bot.isAdmin(sender)) {
sendFailed(message);
return;
}

reply(event, String.format("Current JDA-Butler build used:```\n%s```", BotVersion.FULL_VERSION));
}

@Override
public String getHelp()
{
return null;
}

@Override
public String getName()
{
return "build";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@

public class JDocParser {

//return, funcName, parameters
public static final Pattern METHOD_PATTERN = Pattern.compile("([a-zA-Z.<>?\\[\\]]+)\\s+([a-zA-Z][a-zA-Z0-9]+)\\(([@a-zA-Z0-9\\s.,<>?\\[\\]]*)\\)");
//annos+modifiers, return, funcName, parameters
public static final Pattern METHOD_PATTERN = Pattern.compile("(.*\\s+)?([a-zA-Z.<>?\\[\\]]+)\\s+([a-zA-Z][a-zA-Z0-9]+)\\(([@a-zA-Z0-9\\s.,<>?\\[\\]]*)\\)", Pattern.DOTALL);

//annotations in front of method
public static final Pattern ANNOTATION_PATTERN = Pattern.compile("^((?:@[^\n]+\n)+)");
Expand Down Expand Up @@ -161,7 +161,7 @@ static void parse(final String jdocBase, final String name, final InputStream in
}
}
}
final Element methodSummary = getSingleElementByQuery(document, "a[name=\"method.summary\"]");
final Element methodSummary = getSingleElementByQuery(document, "a[name=\"method.summary\"], a[id=\"method.summary\"]");
classDoc.inheritedMethods.putAll(getInheritedMethods(methodSummary));

//storing
Expand Down Expand Up @@ -208,7 +208,7 @@ private static Map<String, String> getInheritedMethods(Element summaryAnchor) {
if(summaryAnchor == null)
return inherited;
summaryAnchor = summaryAnchor.parent();
Elements inheritAnchors = summaryAnchor.select("a[name^=\"methods.inherited.from.class\"]");
Elements inheritAnchors = summaryAnchor.select("a[name^=\"methods.inherited.from.class\"], a[id^=\"methods.inherited.from.class\"]");
for(Element inheritAnchor : inheritAnchors) {
if(inheritAnchor.siblingElements().size() != 2)
throw new RuntimeException("Got unexpected html while parsing inherited methods from class " + inheritAnchor.attr("name"));
Expand Down Expand Up @@ -358,6 +358,7 @@ public Map<String, List<String>> getFields() {
static class MethodDocumentation implements Documentation {
final ClassDocumentation parent;
final List<MethodAnnotation> methodAnnos;
final boolean isStatic;
final String returnType;
final String functionName;
final String parameters;
Expand All @@ -376,31 +377,34 @@ private MethodDocumentation(ClassDocumentation parent, String functionSig, final
}
//check for documented annotations of method
this.methodAnnos = new ArrayList<>();
Matcher annoGroupMatcher = ANNOTATION_PATTERN.matcher(functionSig);
if(annoGroupMatcher.find()) {
Matcher annoMatcher = ANNOTATION_PARTS.matcher(annoGroupMatcher.group(1));
while(annoMatcher.find()) {
this.methodAnnos.add(new MethodAnnotation(annoMatcher.group(1), annoMatcher.group(2)));
String prefix = methodMatcher.group(1);
if(prefix != null) {
Matcher annoGroupMatcher = ANNOTATION_PATTERN.matcher(prefix);
if(annoGroupMatcher.find()) {
Matcher annoMatcher = ANNOTATION_PARTS.matcher(annoGroupMatcher.group(1));
while(annoMatcher.find()) {
this.methodAnnos.add(new MethodAnnotation(annoMatcher.group(1), annoMatcher.group(2)));
}
}
}
this.parent = parent;
this.returnType = methodMatcher.group(1);
this.functionName = methodMatcher.group(2);
this.parameters = methodMatcher.group(3);
this.isStatic = prefix != null && prefix.contains("static ");
this.returnType = methodMatcher.group(2);
this.functionName = methodMatcher.group(3);
this.parameters = methodMatcher.group(4);
this.functionSig = methodMatcher.group();
this.hashLink = hashLink;
this.desc = desc;
this.fields = fields;

String args = methodMatcher.group(3);
Matcher argMatcher = METHOD_ARG_PATTERN.matcher(args);
Matcher argMatcher = METHOD_ARG_PATTERN.matcher(parameters);
this.argTypes = new ArrayList<>(3);

while(argMatcher.find()) {
this.argTypes.add(argMatcher.group(1).toLowerCase().split("<")[0]);
}

if(!args.isEmpty() && this.argTypes.size() == 0) {
if(!parameters.isEmpty() && this.argTypes.size() == 0) {
throw new RuntimeException("Got non-empty parameters for method " + functionName + " but couldn't parse them. Signature: \"" + functionSig + '\"');
}
}
Expand All @@ -409,11 +413,11 @@ boolean matches(String input, boolean fuzzy) {
final Matcher matcher = METHOD_PATTERN.matcher("ff " + input);
if (!matcher.find())
return false;
if (!matcher.group(2).equalsIgnoreCase(this.functionName))
if (!matcher.group(3).equalsIgnoreCase(this.functionName))
return false;
if (fuzzy)
return true;
final String args = matcher.group(3);
final String args = matcher.group(4);
final String[] split = args.toLowerCase().split(",");
int argLength = args.trim().isEmpty() ? 0 : split.length;
if (argLength != this.argTypes.size())
Expand All @@ -427,7 +431,7 @@ boolean matches(String input, boolean fuzzy) {

@Override
public String getShortTitle() {
return parent.className + '#' + functionName + '(' + parameters + ") : " + returnType;
return parent.className + (isStatic ? '.' : '#') + functionName + '(' + parameters + ") : " + returnType;
}

@Override
Expand Down
22 changes: 15 additions & 7 deletions bot/src/test/java/DocParserRegex.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,45 @@ public class DocParserRegex {
public void testMethodNormal() {
Matcher matcher = JDocParser.METHOD_PATTERN.matcher("void funcName(String a, int b)");
assertTrue("Matcher can't find normal methods", matcher.find());
assertEquals("Matcher doesn't extract function-return correctly", "void", matcher.group(1));
assertEquals("Matcher doesn't extract function-name correctly", "funcName", matcher.group(2));
assertEquals("Matcher doesn't extract function-params correctly", "String a, int b", matcher.group(3));
assertNull("Matcher doesn't extract annos/modifiers correctly", matcher.group(1));
assertEquals("Matcher doesn't extract function-return correctly", "void", matcher.group(2));
assertEquals("Matcher doesn't extract function-name correctly", "funcName", matcher.group(3));
assertEquals("Matcher doesn't extract function-params correctly", "String a, int b", matcher.group(4));
}

@Test
public void testMethodAnnosAndModifiers() {
Matcher matcher = JDocParser.METHOD_PATTERN.matcher("@Deprecated\n@DeprecatedSince(\"testing happened\")\npublic static void funcName(String a, int b)");
assertTrue("Matcher can't find methods with annos/modifiers", matcher.find());
assertEquals("Matcher doesn't extract annos/modifiers correctly", "@Deprecated\n@DeprecatedSince(\"testing happened\")\npublic static ", matcher.group(1));
}

@Test
public void testMethodDots() {
Matcher matcher = JDocParser.METHOD_PATTERN.matcher("java.lang.String funcName(java.lang.String a)");
assertTrue("Matcher can't find methods with dots", matcher.find());
assertEquals("Matcher doesn't extract function-args with dots correctly", "java.lang.String a", matcher.group(3));
assertEquals("Matcher doesn't extract function-args with dots correctly", "java.lang.String a", matcher.group(4));
}

@Test
public void testMethodGenerics() {
Matcher matcher = JDocParser.METHOD_PATTERN.matcher("java.lang.String funcName(Collection<String> a)");
assertTrue("Matcher can't find methods with generics", matcher.find());
assertEquals("Matcher doesn't extract function-args with generics correctly", "Collection<String> a", matcher.group(3));
assertEquals("Matcher doesn't extract function-args with generics correctly", "Collection<String> a", matcher.group(4));
}

@Test
public void testMethodArrays() {
Matcher matcher = JDocParser.METHOD_PATTERN.matcher("void funcName(byte[] a)");
assertTrue("Matcher can't find methods with arrs", matcher.find());
assertEquals("Matcher doesn't extract function-args with arrs correctly", "byte[] a", matcher.group(3));
assertEquals("Matcher doesn't extract function-args with arrs correctly", "byte[] a", matcher.group(4));
}

@Test
public void testMethodCombined() {
Matcher matcher = JDocParser.METHOD_PATTERN.matcher("java.lang.String getInviteUrl(java.util.Collection<Permission> permissions, byte[] arr)");
assertTrue("Matcher can't find methods with generics + dots + arrs", matcher.find());
assertEquals("Matcher doesn't extract function-args with generics and correctly", "java.util.Collection<Permission> permissions, byte[] arr", matcher.group(3));
assertEquals("Matcher doesn't extract function-args with generics, dots & arrs correctly", "java.util.Collection<Permission> permissions, byte[] arr", matcher.group(4));
}

@Test
Expand Down
44 changes: 39 additions & 5 deletions bot/src/test/java/JDocParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import com.kantenkugel.discordbot.jdocparser.Documentation;
import com.kantenkugel.discordbot.jdocparser.JDoc;
import com.kantenkugel.discordbot.jdocparser.JDocUtil;
import net.dv8tion.jda.core.AccountType;
import okhttp3.OkHttpClient;
import org.junit.BeforeClass;
import org.junit.Test;
Expand Down Expand Up @@ -33,24 +34,57 @@ public void getMethodWithReturnAndThrows() {
List<Documentation> docs = JDoc.get("messagechannel.getiterablehistory");
assertEquals("MessageChannel.getIterableHistory should be found", 1, docs.size());
Documentation doc = docs.get(0);
assertTrue("Embed should have Return field", doc.getFields().keySet().stream().anyMatch(f -> f.equals("Returns:")));
assertTrue("Embed should have Throws field", doc.getFields().keySet().stream().anyMatch(f -> f.equals("Throws:")));
assertTrue("Embed should have Return field", doc.getFields().containsKey("Returns:"));
assertTrue("Embed should have Throws field", doc.getFields().containsKey("Throws:"));
}

@Test
public void getMethodWithDeprecation() { //will eventually be needed to be swapped out (deprecations get removed)
List<Documentation> docs = JDoc.get("jdabuilder.buildasync");
assertEquals("JDABuilder#buildAsync() should be found", 1, docs.size());
Documentation doc = docs.get(0);
assertTrue("Embed should have Deprecated field", doc.getFields().containsKey("Deprecated:"));
assertTrue("Embed title should contain Deprecated(Since)", doc.getTitle().contains("@Deprecated(Since"));
assertTrue("Embed title should contain ReplaceWith", doc.getTitle().contains("@ReplaceWith("));
}

@Test
public void getMethodWithIncubating() { //will eventually be needed to be swapped out (incubation status changes)
List<Documentation> docs = JDoc.get("game.watching");
assertEquals("Game.watching should be found", 1, docs.size());
Documentation doc = docs.get(0);
assertTrue("Embed should have Incubating field", doc.getFields().containsKey("Incubating:"));
assertTrue("Embed title should contain Incubating", doc.getTitle().contains("@Incubating"));
}

@Test
public void getMethodWithParameter() {
List<Documentation> docs = JDoc.get("jda.getUserById(long)");
assertEquals("JDA.getUserById(long) should be found", 1, docs.size());
Documentation doc = docs.get(0);
assertTrue("Embed should have Parameters field", doc.getFields().keySet().stream().anyMatch(f -> f.equals("Parameters:")));
assertTrue("Embed should have Parameters field", doc.getFields().containsKey("Parameters:"));
}

@Test
public void checkStaticHandling() {
List<Documentation> docs = JDoc.get("Game.playing");
assertEquals("Game.playing should be found", 1, docs.size());
Documentation doc = docs.get(0);
assertTrue("Game.of should be shown as static", doc.getShortTitle().startsWith("Game.playing("));

docs = JDoc.get("JDA#getUsersByName");
assertEquals("JDA#getUsersByName should be found", 1, docs.size());
doc = docs.get(0);
assertTrue("JDA#getUsersByName should be shown as non-static", doc.getShortTitle().startsWith("JDA#getUsersByName("));
}

@Test
public void getEnumClass() {
List<Documentation> docs = JDoc.get("accounttype");
assertEquals("AccountType should be found", 1, docs.size());
Documentation doc = docs.get(0);
assertTrue("Embed should have Throws field", doc.getFields().keySet().stream().anyMatch(f -> f.equals("Values:")));
assertTrue("Embed should have Values field", doc.getFields().containsKey("Values:"));
assertEquals("AccountType value count mismatches", AccountType.values().length, doc.getFields().get("Values:").size());
}

@Test
Expand Down Expand Up @@ -82,7 +116,7 @@ public void checkURL() {
List<Documentation> message = JDoc.get("Message");
assertEquals("Message should be found as single result", 1, message.size());
assertEquals("URL of Message docs mismatches",
"https://ci.dv8tion.net/job/JDA/lastSuccessfulBuild/javadoc/net/dv8tion/jda/core/entities/Message.html",
"https://ci.dv8tion.net/job/JDA/javadoc/net/dv8tion/jda/core/entities/Message.html",
message.get(0).getUrl(JDocUtil.JDOCBASE)
);
}
Expand Down
31 changes: 29 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ plugins {
}

allprojects {
def build = System.getenv("BUILD_NUMBER") ?: System.getProperty("BUILD_NUMBER") ?: "DEV"
ext {
buildNumber = build == "DEV" ? build : "#" + build
}

dependencyUpdates.resolutionStrategy = {
componentSelection { rules ->
rules.all { ComponentSelection selection ->
Expand Down Expand Up @@ -39,6 +44,28 @@ subprojects {
}
}

project(':bot') {
//Configurations for run
project(':launcher') {
tasks.run.enabled = false
}
}

/*
Due to gradle not terminating processes run via the run task correctly,
running the launcher results in a stranded (still running) bot process when ctrl+c-ing
*/
//project('launcher') {
// clean.doFirst {
// delete "${project.rootDir}/Bot-all.jar"
// }
//
// run {
// systemProperties System.properties
// dependsOn ':bot:shadowJar'
// doFirst {
// copy {
// from project(':bot').buildDir.toPath().resolve('libs/Bot-all.jar')
// into project.rootDir
// }
// }
// }
//}