diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index afe5444f91..8b335103a5 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -8,7 +8,7 @@ }, "features": { "ghcr.io/devcontainers/features/java:1": { - "version": "18.0.2.1-tem", + "version": "24-tem", "jdkDistro": "tem", "installGradle": true }, @@ -35,4 +35,4 @@ "postCreateCommand": { "config": "cp application/config.json.template application/config.json" } -} \ No newline at end of file +} diff --git a/.github/workflows/basic-checks.yml b/.github/workflows/basic-checks.yml index 863a69e0da..2619863c74 100644 --- a/.github/workflows/basic-checks.yml +++ b/.github/workflows/basic-checks.yml @@ -3,7 +3,7 @@ name: Basic checks on: [pull_request] env: - JAVA_VERSION: 21 + JAVA_VERSION: 24 jobs: spotless: diff --git a/.github/workflows/code-analysis.yml b/.github/workflows/code-analysis.yml index ba425f7d88..f51c39e724 100644 --- a/.github/workflows/code-analysis.yml +++ b/.github/workflows/code-analysis.yml @@ -8,7 +8,7 @@ on: - cron: '0 20 * * 4' env: - JAVA_VERSION: 21 + JAVA_VERSION: 24 jobs: sonar: diff --git a/.github/workflows/docker-publish.yaml b/.github/workflows/docker-publish.yaml index a539fba120..edd933f799 100644 --- a/.github/workflows/docker-publish.yaml +++ b/.github/workflows/docker-publish.yaml @@ -7,7 +7,7 @@ on: - 'master' env: - JAVA_VERSION: 21 + JAVA_VERSION: 24 jobs: docker: diff --git a/.github/workflows/docker-verify.yaml b/.github/workflows/docker-verify.yaml index c23528646d..560c6f61d9 100644 --- a/.github/workflows/docker-verify.yaml +++ b/.github/workflows/docker-verify.yaml @@ -3,7 +3,7 @@ name: Docker Verify on: [pull_request] env: - JAVA_VERSION: 21 + JAVA_VERSION: 24 jobs: docker: diff --git a/.github/workflows/releases.yaml b/.github/workflows/releases.yaml index 1f4dfa40fa..fbd106930b 100644 --- a/.github/workflows/releases.yaml +++ b/.github/workflows/releases.yaml @@ -10,7 +10,7 @@ defaults: shell: bash env: - JAVA_VERSION: 21 + JAVA_VERSION: 24 jobs: diff --git a/README.md b/README.md index 846e897549..3c9c50cb40 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # TJ-Bot [![codefactor](https://img.shields.io/codefactor/grade/github/together-java/tj-bot)](https://www.codefactor.io/repository/github/together-java/tj-bot) -![Java](https://img.shields.io/badge/Java-21-ff696c) +![Java](https://img.shields.io/badge/Java-24-ff696c) [![license](https://img.shields.io/github/license/Together-Java/TJ-Bot)](https://github.com/Together-Java/TJ-Bot/blob/master/LICENSE) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/Together-Java/TJ-Bot?label=release) diff --git a/application/build.gradle b/application/build.gradle index 7be2660eee..78c3254c47 100644 --- a/application/build.gradle +++ b/application/build.gradle @@ -1,12 +1,12 @@ buildscript { dependencies { - classpath 'org.xerial:sqlite-jdbc:3.47.1.0' + classpath 'org.xerial:sqlite-jdbc:3.50.1.0' } } plugins { id 'application' - id 'com.google.cloud.tools.jib' version '3.4.0' + id 'com.google.cloud.tools.jib' version '3.4.5' id 'com.github.johnrengelman.shadow' version '8.1.1' id 'database-settings' } @@ -18,7 +18,7 @@ repositories { var outputImage = 'togetherjava.org:5001/togetherjava/tjbot:' + System.getenv('BRANCH_NAME') ?: 'latest' jib { - from.image = 'eclipse-temurin:21' + from.image = 'eclipse-temurin:24' to { image = outputImage auth { @@ -46,18 +46,18 @@ dependencies { implementation project(':utils') implementation project(':formatter') - implementation 'net.dv8tion:JDA:5.2.1' + implementation 'net.dv8tion:JDA:5.6.1' - implementation 'org.apache.logging.log4j:log4j-core:2.24.3' - runtimeOnly 'org.apache.logging.log4j:log4j-slf4j18-impl:2.18.0' + implementation 'org.apache.logging.log4j:log4j-core:2.25.0' + runtimeOnly 'org.apache.logging.log4j:log4j-slf4j2-impl:2.25.0' - implementation 'club.minnced:discord-webhooks:0.8.2' + implementation 'club.minnced:discord-webhooks:0.8.4' implementation "org.jooq:jooq:$jooqVersion" implementation 'io.mikael:urlbuilder:2.0.9' - implementation 'org.jsoup:jsoup:1.18.1' + implementation 'org.jsoup:jsoup:1.21.1' implementation 'org.scilab.forge:jlatexmath:1.0.7' implementation 'org.scilab.forge:jlatexmath-font-greek:1.0.7' @@ -67,24 +67,24 @@ dependencies { implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jacksonVersion" implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-xml:$jacksonVersion" implementation "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion" - implementation "com.sigpwned:jackson-modules-java17-sealed-classes:0.0.0" + implementation "com.sigpwned:jackson-modules-java17-sealed-classes:2.19.0.0" implementation 'com.github.freva:ascii-table:1.8.0' implementation 'io.github.url-detector:url-detector:0.1.23' - implementation 'com.github.ben-manes.caffeine:caffeine:3.1.1' + implementation 'com.github.ben-manes.caffeine:caffeine:3.2.0' - implementation 'org.kohsuke:github-api:1.326' + implementation 'org.kohsuke:github-api:1.327' - implementation 'org.apache.commons:commons-text:1.12.0' - implementation 'com.apptasticsoftware:rssreader:3.8.1' + implementation 'org.apache.commons:commons-text:1.13.1' + implementation 'com.apptasticsoftware:rssreader:3.9.3' - testImplementation 'org.mockito:mockito-core:5.17.0' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.4' - testImplementation 'org.junit.jupiter:junit-jupiter-params:5.11.0' + testImplementation 'org.mockito:mockito-core:5.18.0' + testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" + testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion" testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.1' + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" implementation "com.theokanning.openai-gpt3-java:api:$chatGPTVersion" implementation "com.theokanning.openai-gpt3-java:service:$chatGPTVersion" @@ -92,4 +92,5 @@ dependencies { application { mainClass = 'org.togetherjava.tjbot.Application' + applicationDefaultJvmArgs = ["--enable-native-access=ALL-UNNAMED"] } diff --git a/application/config.json.template b/application/config.json.template index a32f8fd440..3e568329a1 100644 --- a/application/config.json.template +++ b/application/config.json.template @@ -167,9 +167,9 @@ "rssConfig": { "feeds": [ { - "url": "https://wiki.openjdk.org/spaces/createrssfeed.action?types=page&types=comment&types=blogpost&types=mail&types=attachment&spaces=JDKUpdates&maxResults=15&title=%5BJDK+Updates%5D+All+Content+Feed&publicFeed=true", + "url": "https://blogs.oracle.com/java/rss", "targetChannelPattern": "java-news-and-changes", - "dateFormatterPattern": "yyyy-MM-dd'T'HH:mm:ssX" + "dateFormatterPattern": "EEE, d MMM yyyy HH:mm:ss z" } ], "fallbackChannelPattern": "java-news-and-changes", diff --git a/application/src/main/java/org/togetherjava/tjbot/features/BotCommandAdapter.java b/application/src/main/java/org/togetherjava/tjbot/features/BotCommandAdapter.java index 471222df2a..a341f99884 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/BotCommandAdapter.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/BotCommandAdapter.java @@ -5,6 +5,7 @@ import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; import net.dv8tion.jda.api.events.interaction.component.EntitySelectInteractionEvent; import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent; +import net.dv8tion.jda.api.interactions.InteractionContextType; import net.dv8tion.jda.api.interactions.commands.Command; import net.dv8tion.jda.api.interactions.commands.build.CommandData; import org.jetbrains.annotations.Contract; @@ -15,6 +16,7 @@ import java.util.List; import java.util.Objects; +import java.util.Set; /** * Adapter implementation of a {@link BotCommand}. The minimal setup only requires implementation of @@ -51,7 +53,14 @@ public abstract class BotCommandAdapter implements BotCommand { * @param visibility the visibility of the command */ protected BotCommandAdapter(CommandData data, CommandVisibility visibility) { - this.data = data.setGuildOnly(visibility == CommandVisibility.GUILD); + this.data = data; + + Set contexts = switch (visibility) { + case GUILD -> Set.of(InteractionContextType.GUILD); + case GLOBAL -> InteractionContextType.ALL; + }; + + data.setContexts(contexts); this.visibility = Objects.requireNonNull(visibility, "The visibility shouldn't be null"); name = data.getName(); diff --git a/application/src/main/java/org/togetherjava/tjbot/features/Features.java b/application/src/main/java/org/togetherjava/tjbot/features/Features.java index 99241f5689..6746c7f8a2 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/Features.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/Features.java @@ -34,7 +34,6 @@ import org.togetherjava.tjbot.features.help.HelpThreadMetadataPurger; import org.togetherjava.tjbot.features.help.MarkHelpThreadCloseInDBRoutine; import org.togetherjava.tjbot.features.help.PinnedNotificationRemover; -import org.togetherjava.tjbot.features.javamail.RSSHandlerRoutine; import org.togetherjava.tjbot.features.jshell.JShellCommand; import org.togetherjava.tjbot.features.jshell.JShellEval; import org.togetherjava.tjbot.features.mathcommands.TeXCommand; @@ -66,6 +65,7 @@ import org.togetherjava.tjbot.features.projects.ProjectsThreadCreatedListener; import org.togetherjava.tjbot.features.reminder.RemindRoutine; import org.togetherjava.tjbot.features.reminder.ReminderCommand; +import org.togetherjava.tjbot.features.rss.RSSHandlerRoutine; import org.togetherjava.tjbot.features.system.BotCore; import org.togetherjava.tjbot.features.system.LogLevelCommand; import org.togetherjava.tjbot.features.tags.TagCommand; diff --git a/application/src/main/java/org/togetherjava/tjbot/features/chatgpt/ChatGptCommand.java b/application/src/main/java/org/togetherjava/tjbot/features/chatgpt/ChatGptCommand.java index d58c7d8377..163220d8a5 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/chatgpt/ChatGptCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/chatgpt/ChatGptCommand.java @@ -80,11 +80,11 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { public void onModalSubmitted(ModalInteractionEvent event, List args) { event.deferReply().queue(); - String context = ""; String question = event.getValue(QUESTION_INPUT).getAsString(); - Optional optional = chatGptService.ask(question, context); - if (optional.isPresent()) { + Optional chatgptResponse = + chatGptService.ask(question, "You may use markdown syntax for the response"); + if (chatgptResponse.isPresent()) { userIdToAskedAtCache.put(event.getMember().getId(), Instant.now()); } @@ -93,7 +93,7 @@ public void onModalSubmitted(ModalInteractionEvent event, List args) { Please try again later. """; - String response = optional.orElse(errorResponse); + String response = chatgptResponse.orElse(errorResponse); SelfUser selfUser = event.getJDA().getSelfUser(); MessageEmbed responseEmbed = helper.generateGptResponseEmbed(response, selfUser, question); diff --git a/application/src/main/java/org/togetherjava/tjbot/features/chatgpt/ChatGptService.java b/application/src/main/java/org/togetherjava/tjbot/features/chatgpt/ChatGptService.java index e8b02d04bb..a6fdcbcb9d 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/chatgpt/ChatGptService.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/chatgpt/ChatGptService.java @@ -10,9 +10,10 @@ import org.togetherjava.tjbot.config.Config; +import javax.annotation.Nullable; + import java.time.Duration; import java.util.List; -import java.util.Objects; import java.util.Optional; /** @@ -91,37 +92,33 @@ public ChatGptService(Config config) { * @see ChatGPT * Tokens. */ - public Optional ask(String question, String context) { + public Optional ask(String question, @Nullable String context) { if (isDisabled) { return Optional.empty(); } + String contextText = context == null ? "" : ", Context: %s.".formatted(context); + String fullQuestion = "(KEEP IT CONCISE, NOT MORE THAN 280 WORDS%s) - %s" + .formatted(contextText, question); + + ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), fullQuestion); + ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder() + .model(AI_MODEL) + .messages(List.of(chatMessage)) + .frequencyPenalty(FREQUENCY_PENALTY) + .temperature(TEMPERATURE) + .maxTokens(MAX_TOKENS) + .n(MAX_NUMBER_OF_RESPONSES) + .build(); + logger.debug("ChatGpt Request: {}", fullQuestion); + + String response = null; try { - String instructions = "KEEP IT CONCISE, NOT MORE THAN 280 WORDS"; - String questionWithContext = "context: Category %s on a Java Q&A discord server. %s %s" - .formatted(context, instructions, question); - ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), - Objects.requireNonNull(questionWithContext)); - ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder() - .model(AI_MODEL) - .messages(List.of(chatMessage)) - .frequencyPenalty(FREQUENCY_PENALTY) - .temperature(TEMPERATURE) - .maxTokens(MAX_TOKENS) - .n(MAX_NUMBER_OF_RESPONSES) - .build(); - - String response = openAiService.createChatCompletion(chatCompletionRequest) + response = openAiService.createChatCompletion(chatCompletionRequest) .getChoices() .getFirst() .getMessage() .getContent(); - - if (response == null) { - return Optional.empty(); - } - - return Optional.of(response); } catch (OpenAiHttpException openAiHttpException) { logger.warn( "There was an error using the OpenAI API: {} Code: {} Type: {} Status Code: {}", @@ -131,6 +128,12 @@ public Optional ask(String question, String context) { logger.warn("There was an error using the OpenAI API: {}", runtimeException.getMessage()); } - return Optional.empty(); + + logger.debug("ChatGpt Response: {}", response); + if (response == null) { + return Optional.empty(); + } + + return Optional.of(response); } } diff --git a/application/src/main/java/org/togetherjava/tjbot/features/code/CodeMessageHandler.java b/application/src/main/java/org/togetherjava/tjbot/features/code/CodeMessageHandler.java index 5e9e7b69d9..601f91663f 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/code/CodeMessageHandler.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/code/CodeMessageHandler.java @@ -224,7 +224,7 @@ public void onMessageUpdated(MessageUpdateEvent event) { // Re-apply the current action return codeReplyMessage.editMessageEmbeds(maybeCodeAction.orElseThrow().apply(code)); - }).queue(any -> { + }).queue(_ -> { }, failure -> logger.warn( "Attempted to update a code-reply-message ({}), but failed. The original code-message was {}", codeReplyMessageId, originalMessageId, failure)); @@ -253,7 +253,7 @@ public void onMessageDeleted(MessageDeleteEvent event) { // Delete the code reply as well originalMessageToCodeReply.invalidate(originalMessageId); - event.getChannel().deleteMessageById(codeReplyMessageId).queue(any -> { + event.getChannel().deleteMessageById(codeReplyMessageId).queue(_ -> { }, failure -> logger.warn( "Attempted to delete a code-reply-message ({}), but failed. The original code-message was {}", codeReplyMessageId, originalMessageId, failure)); diff --git a/application/src/main/java/org/togetherjava/tjbot/features/componentids/ComponentIdStore.java b/application/src/main/java/org/togetherjava/tjbot/features/componentids/ComponentIdStore.java index 7ada38e67d..2543a4aa8f 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/componentids/ComponentIdStore.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/componentids/ComponentIdStore.java @@ -165,7 +165,7 @@ public void addComponentIdRemovedListener(Consumer listener) { * @throws InvalidComponentIdFormatException if the given component ID was in an unexpected * format and could not be serialized */ - @SuppressWarnings("WeakerAccess") + @SuppressWarnings({"WeakerAccess", "squid:S2259"}) public Optional get(UUID uuid) { synchronized (storeLock) { // Get it from the cache or, if not found, the database diff --git a/application/src/main/java/org/togetherjava/tjbot/features/github/GitHubReference.java b/application/src/main/java/org/togetherjava/tjbot/features/github/GitHubReference.java index 5592e04592..960587e8a4 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/github/GitHubReference.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/github/GitHubReference.java @@ -236,7 +236,7 @@ Optional findIssue(int id, String targetIssueTitle) { if (issue.getTitle().equals(targetIssueTitle)) { return Optional.of(issue); } - } catch (FileNotFoundException ignored) { + } catch (FileNotFoundException _) { return Optional.empty(); } catch (IOException ex) { throw new UncheckedIOException(ex); @@ -255,7 +255,7 @@ Optional findIssue(int id, long defaultRepoId) { issue = repository.getPullRequest(id); } return Optional.of(issue); - } catch (FileNotFoundException ignored) { + } catch (FileNotFoundException _) { return Optional.empty(); } catch (IOException ex) { throw new UncheckedIOException(ex); diff --git a/application/src/main/java/org/togetherjava/tjbot/features/help/AutoPruneHelperRoutine.java b/application/src/main/java/org/togetherjava/tjbot/features/help/AutoPruneHelperRoutine.java index b04e01776a..6ed381a36e 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/help/AutoPruneHelperRoutine.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/help/AutoPruneHelperRoutine.java @@ -84,23 +84,36 @@ public void runRoutine(JDA jda) { } private void pruneForGuild(Guild guild) { - Instant now = Instant.now(); TextChannel selectRoleChannel = getSelectRolesChannelOptional(guild.getJDA()).orElse(null); + guild.loadMembers() + .onSuccess(members -> pruneCategories(guild, members, selectRoleChannel)) + .onError(throwable -> logger.error("Failed to request all members for auto prune.", + throwable)); + } + + private void pruneCategories(Guild guild, List members, + @Nullable TextChannel selectRoleChannel) { + Instant now = Instant.now(); allCategories.stream() .map(category -> helper.handleFindRoleForCategory(category, guild)) .filter(Optional::isPresent) .map(Optional::orElseThrow) - .forEach(role -> pruneRoleIfFull(role, selectRoleChannel, now)); + .forEach(role -> pruneRoleIfFull(members, role, selectRoleChannel, now)); } - private void pruneRoleIfFull(Role role, @Nullable TextChannel selectRoleChannel, Instant when) { - role.getGuild().findMembersWithRoles(role).onSuccess(members -> { - if (isRoleFull(members)) { - logger.debug("Helper role {} is full, starting to prune.", role.getName()); - pruneRole(role, members, selectRoleChannel, when); - } - }); + private void pruneRoleIfFull(List members, Role targetRole, + @Nullable TextChannel selectRoleChannel, Instant when) { + List withRole = filterForRole(members, targetRole); + + if (isRoleFull(withRole)) { + logger.debug("Helper role {} is full, starting to prune.", targetRole.getName()); + pruneRole(targetRole, withRole, selectRoleChannel, when); + } + } + + private List filterForRole(List members, Role role) { + return members.stream().filter(member -> member.getRoles().contains(role)).toList(); } private boolean isRoleFull(Collection members) { diff --git a/application/src/main/java/org/togetherjava/tjbot/features/help/GuildLeaveCloseThreadListener.java b/application/src/main/java/org/togetherjava/tjbot/features/help/GuildLeaveCloseThreadListener.java index 0e4cff2eba..5d1a4d7260 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/help/GuildLeaveCloseThreadListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/help/GuildLeaveCloseThreadListener.java @@ -36,7 +36,7 @@ public void onGuildMemberRemove(GuildMemberRemoveEvent event) { .filter(thread -> thread.getOwnerIdLong() == event.getUser().getIdLong()) .filter(thread -> thread.getParentChannel().getName().matches(helpForumPattern)) .forEach(thread -> thread.sendMessageEmbeds(embed) - .flatMap(any -> thread.getManager().setArchived(true)) + .flatMap(_ -> thread.getManager().setArchived(true)) .queue())); } } diff --git a/application/src/main/java/org/togetherjava/tjbot/features/help/HelpSystemHelper.java b/application/src/main/java/org/togetherjava/tjbot/features/help/HelpSystemHelper.java index 70a96aea7c..222a8bfb66 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/help/HelpSystemHelper.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/help/HelpSystemHelper.java @@ -38,6 +38,8 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.StringJoiner; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -127,26 +129,27 @@ public HelpSystemHelper(Config config, Database database, ChatGptService chatGpt RestAction constructChatGptAttempt(ThreadChannel threadChannel, String originalQuestion, ComponentIdInteractor componentIdInteractor) { Optional questionOptional = prepareChatGptQuestion(threadChannel, originalQuestion); - Optional chatGPTAnswer; + Optional chatGptAnswer; if (questionOptional.isEmpty()) { return useChatGptFallbackMessage(threadChannel); } String question = questionOptional.get(); - logger.debug("The final question sent to chatGPT: {}", question); ForumTag defaultTag = threadChannel.getAppliedTags().getFirst(); ForumTag matchingTag = getCategoryTagOfChannel(threadChannel).orElse(defaultTag); - String context = matchingTag.getName(); - chatGPTAnswer = chatGptService.ask(question, context); + String context = + "Category %s on a Java Q&A discord server. You may use markdown syntax for the response" + .formatted(matchingTag.getName()); + chatGptAnswer = chatGptService.ask(question, context); - if (chatGPTAnswer.isEmpty()) { + if (chatGptAnswer.isEmpty()) { return useChatGptFallbackMessage(threadChannel); } - StringBuilder idForDismissButton = new StringBuilder(); - RestAction message = + AtomicReference messageId = new AtomicReference<>(""); + RestAction post = mentionGuildSlashCommand(threadChannel.getGuild(), ChatGptCommand.COMMAND_NAME) .map(""" Here is an AI assisted attempt to answer your question 🤖. Maybe it helps! \ @@ -154,9 +157,9 @@ RestAction constructChatGptAttempt(ThreadChannel threadChannel, %s. """::formatted) .flatMap(threadChannel::sendMessage) - .onSuccess(m -> idForDismissButton.append(m.getId())); + .onSuccess(message -> messageId.set(message.getId())); - String answer = chatGPTAnswer.orElseThrow(); + String answer = chatGptAnswer.orElseThrow(); SelfUser selfUser = threadChannel.getJDA().getSelfUser(); int responseCharLimit = MessageEmbed.DESCRIPTION_MAX_LENGTH; @@ -165,9 +168,8 @@ RestAction constructChatGptAttempt(ThreadChannel threadChannel, } MessageEmbed responseEmbed = generateGptResponseEmbed(answer, selfUser, originalQuestion); - return message.flatMap(any -> threadChannel.sendMessageEmbeds(responseEmbed) - .addActionRow( - generateDismissButton(componentIdInteractor, idForDismissButton.toString()))); + return post.flatMap(_ -> threadChannel.sendMessageEmbeds(responseEmbed) + .addActionRow(generateDismissButton(componentIdInteractor, messageId.get()))); } /** @@ -204,20 +206,21 @@ private Button generateDismissButton(ComponentIdInteractor componentIdInteractor private Optional prepareChatGptQuestion(ThreadChannel threadChannel, String originalQuestion) { + StringJoiner question = new StringJoiner(" - "); + String questionTitle = threadChannel.getName(); - StringBuilder questionBuilder = new StringBuilder(MAX_QUESTION_LENGTH); + question.add(questionTitle); + question.add(originalQuestion.substring(0, + Math.min(originalQuestion.length(), MAX_QUESTION_LENGTH))); - if (originalQuestion.length() < MIN_QUESTION_LENGTH - && questionTitle.length() < MIN_QUESTION_LENGTH) { + // Not enough content for meaningful responses + if (question.length() < MIN_QUESTION_LENGTH) { return Optional.empty(); } - questionBuilder.append(questionTitle).append(" "); - originalQuestion = originalQuestion.substring(0, Math - .min(MAX_QUESTION_LENGTH - questionBuilder.length(), originalQuestion.length())); - - questionBuilder.append(originalQuestion); - return Optional.of(questionBuilder.toString()); + question.add( + "Additionally to answering the question, provide 3 useful links (as markdown list) from reliable websites on the topic. Write \"Useful links:\" as title for this list."); + return Optional.of(question.toString()); } private RestAction useChatGptFallbackMessage(ThreadChannel threadChannel) { diff --git a/application/src/main/java/org/togetherjava/tjbot/features/help/HelpThreadAutoArchiver.java b/application/src/main/java/org/togetherjava/tjbot/features/help/HelpThreadAutoArchiver.java index 4b0b6a317a..41792957ff 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/help/HelpThreadAutoArchiver.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/help/HelpThreadAutoArchiver.java @@ -151,7 +151,7 @@ private void triggerArchiveFlow(ThreadChannel threadChannel, long authorId, return sendEmbedWithMention.apply(authorResults.get()); }) - .flatMap(any -> threadChannel.getManager().setArchived(true)) + .flatMap(_ -> threadChannel.getManager().setArchived(true)) .queue(); } diff --git a/application/src/main/java/org/togetherjava/tjbot/features/help/HelpThreadCommand.java b/application/src/main/java/org/togetherjava/tjbot/features/help/HelpThreadCommand.java index 0adcd14a22..fd6b264e0c 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/help/HelpThreadCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/help/HelpThreadCommand.java @@ -102,7 +102,7 @@ public HelpThreadCommand(Config config, HelpSystemHelper helper) { .collect(Collectors.toMap(Subcommand::getCommandName, Function.identity())); subcommandToCooldownCache = new EnumMap<>(streamSubcommands() .filter(Subcommand::hasCooldown) - .collect(Collectors.toMap(Function.identity(), any -> createCooldownCache.get()))); + .collect(Collectors.toMap(Function.identity(), _ -> createCooldownCache.get()))); subcommandToEventHandler = new EnumMap<>(Map.of(Subcommand.CHANGE_CATEGORY, this::changeCategory, Subcommand.CHANGE_TITLE, this::changeTitle, Subcommand.CLOSE, this::closeThread, Subcommand.RESET_ACTIVITY, this::resetActivity)); @@ -124,6 +124,7 @@ && isHelpThreadOnCooldown(invokedSubcommand, helpThread)) { subcommandToEventHandler.get(invokedSubcommand).accept(event, helpThread); } + @SuppressWarnings("squid:S2259") private boolean isHelpThreadOnCooldown(Subcommand subcommand, ThreadChannel helpThread) { Cache helpThreadIdToLastAction = requireCooldownCache(subcommand); return Optional.ofNullable(helpThreadIdToLastAction.getIfPresent(helpThread.getIdLong())) @@ -158,7 +159,7 @@ private void changeCategory(SlashCommandInteractionEvent event, ThreadChannel he refreshCooldownFor(Subcommand.CHANGE_CATEGORY, helpThread); helper.changeChannelCategory(helpThread, category) - .flatMap(any -> sendCategoryChangedMessage(helpThread.getGuild(), event.getHook(), + .flatMap(_ -> sendCategoryChangedMessage(helpThread.getGuild(), event.getHook(), helpThread, category)) .queue(); } @@ -185,7 +186,7 @@ private RestAction sendCategoryChangedMessage(Guild guild, InteractionH String headsUpPattern = "%s please have a look, thanks."; String headsUpWithoutRole = headsUpPattern.formatted(""); String headsUpWithRole = headsUpPattern.formatted(helperRole.orElseThrow().getAsMention()); - return action.flatMap(any -> helpThread.sendMessage(headsUpWithoutRole) + return action.flatMap(_ -> helpThread.sendMessage(headsUpWithoutRole) .flatMap(message -> message.editMessage(headsUpWithRole))); } @@ -195,7 +196,7 @@ private void changeTitle(SlashCommandInteractionEvent event, ThreadChannel helpT refreshCooldownFor(Subcommand.CHANGE_TITLE, helpThread); helper.renameChannel(helpThread, title) - .flatMap(any -> event.reply("Changed the title to **%s**.".formatted(title))) + .flatMap(_ -> event.reply("Changed the title to **%s**.".formatted(title))) .queue(); } @@ -206,7 +207,7 @@ private void closeThread(SlashCommandInteractionEvent event, ThreadChannel helpT .setColor(HelpSystemHelper.AMBIENT_COLOR) .build(); - event.replyEmbeds(embed).flatMap(any -> helpThread.getManager().setArchived(true)).queue(); + event.replyEmbeds(embed).flatMap(_ -> helpThread.getManager().setArchived(true)).queue(); } private void resetActivity(SlashCommandInteractionEvent event, ThreadChannel helpThread) { diff --git a/application/src/main/java/org/togetherjava/tjbot/features/help/HelpThreadCreatedListener.java b/application/src/main/java/org/togetherjava/tjbot/features/help/HelpThreadCreatedListener.java index 12ee788fa1..cd453eab63 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/help/HelpThreadCreatedListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/help/HelpThreadCreatedListener.java @@ -76,7 +76,7 @@ private boolean wasThreadAlreadyHandled(long threadChannelId) { // the threads we already handled Instant now = Instant.now(); // NOTE It is necessary to do the "check if exists, otherwise insert" atomic - Instant createdAt = threadIdToCreatedAtCache.get(threadChannelId, any -> now); + Instant createdAt = threadIdToCreatedAtCache.get(threadChannelId, _ -> now); return createdAt != now; } @@ -84,9 +84,9 @@ private void handleHelpThreadCreated(ThreadChannel threadChannel) { threadChannel.retrieveStartMessage().flatMap(message -> { registerThreadDataInDB(message, threadChannel); return sendHelperHeadsUp(threadChannel) - .flatMap(any -> HelpThreadCreatedListener.isContextSufficient(message), - any -> createAIResponse(threadChannel, message)) - .flatMap(any -> pinOriginalQuestion(message)); + .flatMap(_ -> HelpThreadCreatedListener.isContextSufficient(message), + _ -> createAIResponse(threadChannel, message)) + .flatMap(_ -> pinOriginalQuestion(message)); }).queue(); } diff --git a/application/src/main/java/org/togetherjava/tjbot/features/jshell/renderer/RendererUtils.java b/application/src/main/java/org/togetherjava/tjbot/features/jshell/renderer/RendererUtils.java index 9d44c0df57..c36695af77 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/jshell/renderer/RendererUtils.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/jshell/renderer/RendererUtils.java @@ -23,12 +23,12 @@ private RendererUtils() {} static String abortionCauseToString(JShellEvalAbortionCause abortionCause) { return switch (abortionCause) { - case JShellEvalAbortionCause.TimeoutAbortionCause ignored -> "Allowed time exceeded."; + case JShellEvalAbortionCause.TimeoutAbortionCause _ -> "Allowed time exceeded."; case JShellEvalAbortionCause.UnhandledExceptionAbortionCause(String exceptionClass, String exceptionMessage) -> "Uncaught exception:\n" + exceptionClass + ":" + exceptionMessage; case JShellEvalAbortionCause.CompileTimeErrorAbortionCause(List errors) -> "The code doesn't compile:\n" + String.join("\n", errors); - case JShellEvalAbortionCause.SyntaxErrorAbortionCause ignored -> + case JShellEvalAbortionCause.SyntaxErrorAbortionCause _ -> "The code doesn't compile, there are syntax errors in this code."; }; } diff --git a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java index 083dd193ec..11f666beaa 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java @@ -46,7 +46,7 @@ public void onMessageReceived(MessageReceivedEvent event) { } if (messageHasNoMediaAttached(message)) { - message.delete().flatMap(any -> dmUser(message)).queue(any -> { + message.delete().flatMap(_ -> dmUser(message)).queue(_ -> { }, failure -> tempNotifyUserInChannel(message)); } } diff --git a/application/src/main/java/org/togetherjava/tjbot/features/moderation/ReportCommand.java b/application/src/main/java/org/togetherjava/tjbot/features/moderation/ReportCommand.java index 61eeb0f3ae..ced7aaec4a 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/moderation/ReportCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/moderation/ReportCommand.java @@ -125,6 +125,7 @@ private boolean handleIsOnCooldown(MessageContextInteractionEvent event) { return true; } + @SuppressWarnings("squid:S2259") private boolean isAuthorOnCooldown(long userId) { return Optional.ofNullable(authorToLastReportInvocation.getIfPresent(userId)) .map(sinceCommandInvoked -> sinceCommandInvoked.plus(COOLDOWN_DURATION_VALUE, diff --git a/application/src/main/java/org/togetherjava/tjbot/features/moderation/TransferQuestionCommand.java b/application/src/main/java/org/togetherjava/tjbot/features/moderation/TransferQuestionCommand.java index 58ad3a5766..69e59f9358 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/moderation/TransferQuestionCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/moderation/TransferQuestionCommand.java @@ -17,7 +17,6 @@ import net.dv8tion.jda.api.exceptions.ErrorResponseException; import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.components.text.TextInput; -import net.dv8tion.jda.api.interactions.components.text.TextInput.Builder; import net.dv8tion.jda.api.interactions.components.text.TextInputStyle; import net.dv8tion.jda.api.interactions.modals.Modal; import net.dv8tion.jda.api.requests.ErrorResponse; @@ -86,7 +85,6 @@ public TransferQuestionCommand(Config config, ChatGptService chatGptService) { @Override public void onMessageContext(MessageContextInteractionEvent event) { - if (isInvalidForTransfer(event)) { return; } @@ -96,11 +94,12 @@ public void onMessageContext(MessageContextInteractionEvent event) { String originalChannelId = event.getTarget().getChannel().getId(); String authorId = event.getTarget().getAuthor().getId(); String mostCommonTag = tags.getFirst(); - String chatGptPrompt = - "Summarize the following text into a concise title or heading not more than 4-5 words, remove quotations if any: %s" + + String chatGptTitleRequest = + "Summarize the following question into a concise title or heading not more than 5 words, remove quotations if any: %s" .formatted(originalMessage); - Optional chatGptResponse = chatGptService.ask(chatGptPrompt, ""); - String title = chatGptResponse.orElse(createTitle(originalMessage)); + Optional chatGptTitle = chatGptService.ask(chatGptTitleRequest, null); + String title = chatGptTitle.orElse(createTitle(originalMessage)); if (title.length() > TITLE_MAX_LENGTH) { title = title.substring(0, TITLE_MAX_LENGTH); } @@ -112,7 +111,7 @@ public void onMessageContext(MessageContextInteractionEvent event) { .setValue(title) .build(); - Builder modalInputBuilder = + TextInput.Builder modalInputBuilder = TextInput.create(MODAL_INPUT_ID, "Question", TextInputStyle.PARAGRAPH) .setRequiredRange(INPUT_MIN_LENGTH, INPUT_MAX_LENGTH) .setPlaceholder("Contents of the question"); @@ -150,7 +149,7 @@ public void onModalSubmitted(ModalInteractionEvent event, List args) { // Has been handled if original message was deleted by now. // Deleted messages cause retrieveMessageById to fail. Consumer notHandledAction = - any -> transferFlow(event, channelId, authorId, messageId); + _ -> transferFlow(event, channelId, authorId, messageId); Consumer handledAction = failure -> { if (failure instanceof ErrorResponseException errorResponseException diff --git a/application/src/main/java/org/togetherjava/tjbot/features/moderation/attachment/BlacklistedAttachmentListener.java b/application/src/main/java/org/togetherjava/tjbot/features/moderation/attachment/BlacklistedAttachmentListener.java index db1060aefb..c7cd224f18 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/moderation/attachment/BlacklistedAttachmentListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/moderation/attachment/BlacklistedAttachmentListener.java @@ -49,7 +49,7 @@ public void onMessageReceived(MessageReceivedEvent event) { } private void handleBadMessage(Message message) { - message.delete().flatMap(any -> dmUser(message)).queue(any -> warnMods(message)); + message.delete().flatMap(_ -> dmUser(message)).queue(_ -> warnMods(message)); } private RestAction dmUser(Message message) { diff --git a/application/src/main/java/org/togetherjava/tjbot/features/moderation/modmail/ModMailCommand.java b/application/src/main/java/org/togetherjava/tjbot/features/moderation/modmail/ModMailCommand.java index 3395a8c828..b43748ec7a 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/moderation/modmail/ModMailCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/moderation/modmail/ModMailCommand.java @@ -47,7 +47,7 @@ public final class ModMailCommand extends SlashCommandAdapter { private static final Logger logger = LoggerFactory.getLogger(ModMailCommand.class); public static final String COMMAND_NAME = "modmail"; private static final String OPTION_MESSAGE = "message"; - private static final String OPTION_STAY_ANONYMOUS = "stay-anonymous"; + private static final String OPTION_REVEAL_NAME = "reveal-name"; private static final String OPTION_GUILD = "server"; private static final int COOLDOWN_DURATION_VALUE = 30; private static final ChronoUnit COOLDOWN_DURATION_UNIT = ChronoUnit.MINUTES; @@ -70,8 +70,9 @@ public ModMailCommand(JDA jda, Config config) { OptionData guildOption = new OptionData(OptionType.STRING, OPTION_GUILD, "The server to contact mods from", true); - OptionData anonymousOption = new OptionData(OptionType.BOOLEAN, OPTION_STAY_ANONYMOUS, - "If set, your name is hidden - note that mods then can not get back to you", true); + OptionData revealNameOption = new OptionData(OptionType.BOOLEAN, OPTION_REVEAL_NAME, + "If set, your name is shown to mods - false means mods can not get back to you", + true); List choices = jda.getGuildCache() .stream() @@ -80,7 +81,7 @@ public ModMailCommand(JDA jda, Config config) { guildOption.addChoices(choices); - getData().addOptions(guildOption, anonymousOption); + getData().addOptions(guildOption, revealNameOption); modMailChannelNamePredicate = Pattern.compile(config.getModMailChannelPattern()).asMatchPredicate(); @@ -112,7 +113,7 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { private void sendMessageModal(SlashCommandInteractionEvent event) { long userGuildId = event.getOption(OPTION_GUILD).getAsLong(); - boolean wantsToStayAnonymous = event.getOption(OPTION_STAY_ANONYMOUS).getAsBoolean(); + boolean wantsToRevealName = event.getOption(OPTION_REVEAL_NAME).getAsBoolean(); TextInput message = TextInput.create(OPTION_MESSAGE, "Your message", TextInputStyle.PARAGRAPH) @@ -120,8 +121,8 @@ private void sendMessageModal(SlashCommandInteractionEvent event) { .setMinLength(3) .build(); - String componentId = generateComponentId(String.valueOf(userGuildId), - String.valueOf(wantsToStayAnonymous)); + String componentId = + generateComponentId(String.valueOf(userGuildId), String.valueOf(wantsToRevealName)); Modal modal = Modal.create(componentId, "Send message to moderators") .addActionRow(message) @@ -136,7 +137,7 @@ public void onModalSubmitted(ModalInteractionEvent event, List args) { long userId = event.getUser().getIdLong(); long userGuildId = Long.parseLong(args.getFirst()); - boolean wantsToStayAnonymous = Boolean.parseBoolean(args.get(1)); + boolean wantsToRevealName = Boolean.parseBoolean(args.get(1)); Optional modMailAuditLog = getModMailChannel(event.getJDA(), userGuildId); if (modMailAuditLog.isEmpty()) { @@ -148,7 +149,7 @@ public void onModalSubmitted(ModalInteractionEvent event, List args) { event.deferReply().setEphemeral(true).queue(); MessageCreateAction message = createModMessage(event, userId, userMessage, - wantsToStayAnonymous, modMailAuditLog.orElseThrow()); + wantsToRevealName, modMailAuditLog.orElseThrow()); sendMessage(event, message); } @@ -172,11 +173,11 @@ private Optional getModMailChannel(JDA jda, long guildId) { } private MessageCreateAction createModMessage(ModalInteractionEvent event, long userId, - String userMessage, boolean wantsToStayAnonymous, TextChannel modMailAuditLog) { - User user = wantsToStayAnonymous ? null : event.getUser(); + String userMessage, boolean wantsToRevealName, TextChannel modMailAuditLog) { + User user = wantsToRevealName ? event.getUser() : null; MessageCreateAction message = modMailAuditLog.sendMessageEmbeds(createModMailMessage(user, userMessage)); - if (!wantsToStayAnonymous) { + if (wantsToRevealName) { message.addActionRow(DiscordClientAction.General.USER.asLinkButton("Author Profile", String.valueOf(userId))); } @@ -213,6 +214,7 @@ private MessageEmbed createModMailMessage(@Nullable User author, String userMess .build(); } + @SuppressWarnings("squid:S2259") private boolean isChannelOnCooldown(long userId) { return Optional.ofNullable(authorToLastModMailInvocation.getIfPresent(userId)) .map(sinceCommandInvoked -> sinceCommandInvoked.plus(COOLDOWN_DURATION_VALUE, diff --git a/application/src/main/java/org/togetherjava/tjbot/features/moderation/scam/ScamBlocker.java b/application/src/main/java/org/togetherjava/tjbot/features/moderation/scam/ScamBlocker.java index 0816e2fb5c..057a71cee6 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/moderation/scam/ScamBlocker.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/moderation/scam/ScamBlocker.java @@ -273,7 +273,7 @@ private void dmUser(MessageReceivedEvent event) { } private void dmUser(Guild guild, long userId, JDA jda) { - jda.openPrivateChannelById(userId).flatMap(channel -> dmUser(guild, channel)).queue(any -> { + jda.openPrivateChannelById(userId).flatMap(channel -> dmUser(guild, channel)).queue(_ -> { }, failure -> logger.debug( "Unable to send dm message to user {} in guild {} to inform them about a scam message being blocked", userId, guild.getId(), failure)); diff --git a/application/src/main/java/org/togetherjava/tjbot/features/moderation/scam/ScamDetector.java b/application/src/main/java/org/togetherjava/tjbot/features/moderation/scam/ScamDetector.java index c4ebed3657..33a9a28743 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/moderation/scam/ScamDetector.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/moderation/scam/ScamDetector.java @@ -80,7 +80,7 @@ private void analyzeUrl(String url, AnalyseResults results) { String host; try { host = URI.create(url).getHost(); - } catch (IllegalArgumentException e) { + } catch (IllegalArgumentException _) { // Invalid urls are not scam return; } diff --git a/application/src/main/java/org/togetherjava/tjbot/features/reminder/RemindRoutine.java b/application/src/main/java/org/togetherjava/tjbot/features/reminder/RemindRoutine.java index 1da5871a1d..0f2f0417d2 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/reminder/RemindRoutine.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/reminder/RemindRoutine.java @@ -154,7 +154,7 @@ Failed to send a reminder with (authorID '{}') skipping it. This can be due to a int failureAttempts = pendingReminder.getFailureAttempts() + 1; Instant remindAt = Instant.now().plus(1, ChronoUnit.MINUTES); - database.write(any -> { + database.write(_ -> { pendingReminder.setRemindAt(remindAt); pendingReminder.setFailureAttempts(failureAttempts); pendingReminder.insert(); diff --git a/application/src/main/java/org/togetherjava/tjbot/features/javamail/RSSHandlerRoutine.java b/application/src/main/java/org/togetherjava/tjbot/features/rss/RSSHandlerRoutine.java similarity index 97% rename from application/src/main/java/org/togetherjava/tjbot/features/javamail/RSSHandlerRoutine.java rename to application/src/main/java/org/togetherjava/tjbot/features/rss/RSSHandlerRoutine.java index e114f53a61..c86f305cda 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/javamail/RSSHandlerRoutine.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/rss/RSSHandlerRoutine.java @@ -1,4 +1,4 @@ -package org.togetherjava.tjbot.features.javamail; +package org.togetherjava.tjbot.features.rss; import com.apptasticsoftware.rssreader.Item; import com.apptasticsoftware.rssreader.RssReader; @@ -74,6 +74,8 @@ public final class RSSHandlerRoutine implements Routine { private static final int MAX_CONTENTS = 1000; private static final ZonedDateTime ZONED_TIME_MIN = ZonedDateTime.of(LocalDateTime.MIN, ZoneId.systemDefault()); + private static final String HTTP_USER_AGENT = + "TJ-Bot/1.0 (+https://github.com/Together-Java/TJ-Bot)"; private final RssReader rssReader; private final RSSFeedsConfig config; private final Predicate fallbackChannelPattern; @@ -101,7 +103,9 @@ public RSSHandlerRoutine(Config config, Database database) { targetChannelPatterns.put(feed, predicate); } }); + this.rssReader = new RssReader(); + this.rssReader.setUserAgent(HTTP_USER_AGENT); } @Override @@ -210,7 +214,7 @@ private Optional getLastSavedDateFromDatabaseRecord(RssFeedRecord ZonedDateTime savedDate = getZonedDateTime(rssRecord.getLastDate(), dateFormatterPattern); return Optional.of(savedDate); - } catch (DateTimeParseException e) { + } catch (DateTimeParseException _) { return Optional.empty(); } } @@ -313,7 +317,7 @@ private static boolean isValidDateFormat(Item rssItem, RSSFeed feedConfig) { // that the format pattern defined in the config and the // feed's actual format differ. getZonedDateTime(firstRssFeedPubDate.get(), feedConfig.dateFormatterPattern()); - } catch (DateTimeParseException e) { + } catch (DateTimeParseException _) { return false; } return true; @@ -391,7 +395,7 @@ private List fetchRSSItemsFromURL(String rssUrl) { try { return rssReader.read(rssUrl).toList(); } catch (IOException e) { - logger.warn("Could not fetch RSS from URL ({})", rssUrl); + logger.error("Could not fetch RSS from URL ({})", rssUrl, e); return List.of(); } } diff --git a/application/src/main/java/org/togetherjava/tjbot/features/javamail/package-info.java b/application/src/main/java/org/togetherjava/tjbot/features/rss/package-info.java similarity index 83% rename from application/src/main/java/org/togetherjava/tjbot/features/javamail/package-info.java rename to application/src/main/java/org/togetherjava/tjbot/features/rss/package-info.java index 36305399af..a08df6e828 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/javamail/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/rss/package-info.java @@ -3,7 +3,7 @@ */ @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault -package org.togetherjava.tjbot.features.javamail; +package org.togetherjava.tjbot.features.rss; import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/features/tags/TagManageCommand.java b/application/src/main/java/org/togetherjava/tjbot/features/tags/TagManageCommand.java index eb7dbecbe9..c720775ad8 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/tags/TagManageCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/tags/TagManageCommand.java @@ -130,7 +130,7 @@ private static void sendSuccessMessage(IReplyCallback event, String id, String a private static OptionalLong parseMessageIdAndHandle(String messageId, IReplyCallback event) { try { return OptionalLong.of(Long.parseLong(messageId)); - } catch (NumberFormatException e) { + } catch (NumberFormatException _) { event .reply("The given message id '%s' is invalid, expected a number." .formatted(messageId)) @@ -297,7 +297,7 @@ private Optional getTagContent(Subcommand subcommand, String id) { if (Subcommand.SUBCOMMANDS_WITH_PREVIOUS_CONTENT.contains(subcommand)) { try { return tagSystem.getTag(id); - } catch (NoSuchElementException e) { + } catch (NoSuchElementException _) { // NOTE Rare race condition, for example if another thread deleted the tag in the // meantime logger.warn("Tried to retrieve content of tag '{}', but the content doesn't exist.", diff --git a/application/src/main/java/org/togetherjava/tjbot/features/utils/LinkPreviews.java b/application/src/main/java/org/togetherjava/tjbot/features/utils/LinkPreviews.java index cc84fa3083..6126e05e57 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/utils/LinkPreviews.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/utils/LinkPreviews.java @@ -63,7 +63,7 @@ public static CompletableFuture> createLinkPreviews(List extractResults(tasks)).exceptionally(e -> { + return allDoneTask.thenApply(_ -> extractResults(tasks)).exceptionally(e -> { logger.error("Unknown error during link preview creation", e); return List.of(); }); @@ -184,6 +184,7 @@ private static Optional parseMetaProperty(Document doc, String metaPrope .filter(Predicate.not(String::isBlank)); } + @SuppressWarnings("squid:S2259") private static Optional selectFirstMetaTag(Document doc, String key, String value) { return Optional.ofNullable(doc.selectFirst("meta[%s=%s]".formatted(key, value))) .map(element -> element.attr("content")); diff --git a/application/src/main/java/org/togetherjava/tjbot/logging/discord/DiscordLogging.java b/application/src/main/java/org/togetherjava/tjbot/logging/discord/DiscordLogging.java index 99d2de7970..f7afed7fde 100644 --- a/application/src/main/java/org/togetherjava/tjbot/logging/discord/DiscordLogging.java +++ b/application/src/main/java/org/togetherjava/tjbot/logging/discord/DiscordLogging.java @@ -23,6 +23,7 @@ */ public final class DiscordLogging { private static final Logger logger = LoggerFactory.getLogger(DiscordLogging.class); + private static final String LOG_CHANNEL_WEBHOOK_DEFAULT_VALUE = ""; private DiscordLogging() { throw new UnsupportedOperationException("Utility class"); @@ -45,22 +46,29 @@ public static void startDiscordLogging(Config botConfig) { } private static void addAppenders(Configuration logConfig, Config botConfig) { - parseWebhookUri(botConfig.getLogInfoChannelWebhook()) + parseWebhookUri(botConfig.getLogInfoChannelWebhook(), "info") .ifPresent(webhookUri -> addDiscordLogAppender("DiscordInfo", createInfoRangeFilter(), webhookUri, botConfig.getSourceCodeBaseUrl(), logConfig)); - parseWebhookUri(botConfig.getLogErrorChannelWebhook()) + parseWebhookUri(botConfig.getLogErrorChannelWebhook(), "error") .ifPresent(webhookUri -> addDiscordLogAppender("DiscordError", createErrorRangeFilter(), webhookUri, botConfig.getSourceCodeBaseUrl(), logConfig)); } - private static Optional parseWebhookUri(String webhookUri) { + private static Optional parseWebhookUri(String webhookUri, String webhookName) { + if (webhookUri.equalsIgnoreCase(LOG_CHANNEL_WEBHOOK_DEFAULT_VALUE)) { + logger.warn( + "The {} webhook URL was not setup yet, logs will not be forwarded to Discord. Enter a valid webhook URL in your `config.json` if you want log forwarding.", + webhookName); + return Optional.empty(); + } + try { return Optional.of(URI.create(webhookUri)); } catch (IllegalArgumentException e) { logger.warn(LogMarkers.NO_DISCORD, - "The webhook URL ({}) in the config is invalid, logs will not be forwarded to Discord.", - webhookUri, e); + "The {} webhook URL ({}) in the config is invalid, logs will not be forwarded to Discord.", + webhookName, webhookUri, e); return Optional.empty(); } } diff --git a/application/src/test/java/org/togetherjava/tjbot/features/SlashCommandAdapterTest.java b/application/src/test/java/org/togetherjava/tjbot/features/SlashCommandAdapterTest.java index 745731031b..cff9818d17 100644 --- a/application/src/test/java/org/togetherjava/tjbot/features/SlashCommandAdapterTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/features/SlashCommandAdapterTest.java @@ -15,7 +15,6 @@ final class SlashCommandAdapterTest { UserInteractionType.SLASH_COMMAND.getPrefix() + NAME; private static final String DESCRIPTION = "Foo command"; private static final CommandVisibility VISIBILITY = CommandVisibility.GUILD; - private static final int UNIQUE_ID_ITERATIONS = 20; static SlashCommandAdapter createAdapter() { // noinspection AnonymousInnerClass diff --git a/application/src/test/java/org/togetherjava/tjbot/jda/ButtonClickEventBuilder.java b/application/src/test/java/org/togetherjava/tjbot/jda/ButtonClickEventBuilder.java index a2a474dbcc..140bfc8e0f 100644 --- a/application/src/test/java/org/togetherjava/tjbot/jda/ButtonClickEventBuilder.java +++ b/application/src/test/java/org/togetherjava/tjbot/jda/ButtonClickEventBuilder.java @@ -1,6 +1,5 @@ package org.togetherjava.tjbot.jda; -import com.fasterxml.jackson.databind.ObjectMapper; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageEmbed; @@ -67,7 +66,6 @@ * */ public final class ButtonClickEventBuilder { - private static final ObjectMapper JSON = new ObjectMapper(); private final JdaTester jdaTester; private final Supplier mockEventSupplier; private final UnaryOperator mockMessageOperator; diff --git a/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java b/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java index ce6458fb0f..bf42857817 100644 --- a/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java +++ b/application/src/test/java/org/togetherjava/tjbot/jda/JdaTester.java @@ -31,9 +31,9 @@ import net.dv8tion.jda.api.requests.SequentialRestRateLimiter; import net.dv8tion.jda.api.requests.restaction.CacheRestAction; import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction; -import net.dv8tion.jda.api.utils.AttachmentProxy; import net.dv8tion.jda.api.utils.ConcurrentSessionController; import net.dv8tion.jda.api.utils.FileUpload; +import net.dv8tion.jda.api.utils.NamedAttachmentProxy; import net.dv8tion.jda.api.utils.cache.CacheFlag; import net.dv8tion.jda.api.utils.messages.MessageCreateData; import net.dv8tion.jda.api.utils.messages.MessageEditData; @@ -770,7 +770,7 @@ public Message clientMessageToReceivedMessageMock(MessageCreateData clientMessag private Message.Attachment clientAttachmentToReceivedAttachmentMock( FileUpload clientAttachment) { Message.Attachment receivedAttachment = mock(Message.Attachment.class); - AttachmentProxy attachmentProxy = mock(AttachmentProxy.class); + NamedAttachmentProxy attachmentProxy = mock(NamedAttachmentProxy.class); when(receivedAttachment.getJDA()).thenReturn(jda); when(receivedAttachment.getFileName()).thenReturn(clientAttachment.getName()); diff --git a/application/src/test/java/org/togetherjava/tjbot/jda/SlashCommandInteractionEventBuilder.java b/application/src/test/java/org/togetherjava/tjbot/jda/SlashCommandInteractionEventBuilder.java index 77533a44df..9206e428da 100644 --- a/application/src/test/java/org/togetherjava/tjbot/jda/SlashCommandInteractionEventBuilder.java +++ b/application/src/test/java/org/togetherjava/tjbot/jda/SlashCommandInteractionEventBuilder.java @@ -5,15 +5,19 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.IntegrationOwners; +import net.dv8tion.jda.api.interactions.InteractionContextType; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.api.utils.data.DataObject; import net.dv8tion.jda.internal.JDAImpl; +import net.dv8tion.jda.internal.interactions.IntegrationOwnersImpl; import net.dv8tion.jda.internal.interactions.command.SlashCommandInteractionImpl; import org.togetherjava.tjbot.features.SlashCommand; import org.togetherjava.tjbot.jda.payloads.PayloadChannel; +import org.togetherjava.tjbot.jda.payloads.PayloadGuild; import org.togetherjava.tjbot.jda.payloads.PayloadMember; import org.togetherjava.tjbot.jda.payloads.PayloadUser; import org.togetherjava.tjbot.jda.payloads.slashcommand.PayloadSlashCommand; @@ -28,6 +32,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.stream.Collectors; @@ -278,6 +283,8 @@ private PayloadSlashCommand createEvent() { "1099511627775", List.of(), false, false, false, null, false, user); PayloadChannel channel = new PayloadChannel(channelId, 1); + PayloadGuild guild = new PayloadGuild(Long.parseLong(guildId), "en-US", Set.of()); + List options; if (subcommand == null) { options = extractOptionsOrNull(nameToOption); @@ -288,8 +295,11 @@ private PayloadSlashCommand createEvent() { PayloadSlashCommandData data = new PayloadSlashCommandData(command.getName(), "1", 1, options, extractResolvedOrNull(nameToOption)); + IntegrationOwners owners = new IntegrationOwnersImpl(DataObject.empty()); + return new PayloadSlashCommand(guildId, "897425767397466123", 2, 1, applicationId, token, - member, channel, data); + member, channel, guild, data, Long.parseLong(channelId), + InteractionContextType.PRIVATE_CHANNEL, owners); } @Nullable diff --git a/application/src/test/java/org/togetherjava/tjbot/jda/payloads/PayloadGuild.java b/application/src/test/java/org/togetherjava/tjbot/jda/payloads/PayloadGuild.java new file mode 100644 index 0000000000..d2524691dd --- /dev/null +++ b/application/src/test/java/org/togetherjava/tjbot/jda/payloads/PayloadGuild.java @@ -0,0 +1,44 @@ +package org.togetherjava.tjbot.jda.payloads; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Set; + +public class PayloadGuild { + + private long id; + @JsonProperty("preferred_locale") + private String preferredLocale; + private Set features; + + public PayloadGuild(long id, String preferredLocale, Set features) { + this.id = id; + this.preferredLocale = preferredLocale; + this.features = features; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getPreferredLocale() { + return preferredLocale; + } + + public void setPreferredLocale(String preferredLocale) { + this.preferredLocale = preferredLocale; + } + + public Set getFeatures() { + return features; + } + + public void setFeatures(Set features) { + this.features = features; + } + +} diff --git a/application/src/test/java/org/togetherjava/tjbot/jda/payloads/slashcommand/PayloadSlashCommand.java b/application/src/test/java/org/togetherjava/tjbot/jda/payloads/slashcommand/PayloadSlashCommand.java index 8108d2026d..246744d372 100644 --- a/application/src/test/java/org/togetherjava/tjbot/jda/payloads/slashcommand/PayloadSlashCommand.java +++ b/application/src/test/java/org/togetherjava/tjbot/jda/payloads/slashcommand/PayloadSlashCommand.java @@ -1,8 +1,11 @@ package org.togetherjava.tjbot.jda.payloads.slashcommand; import com.fasterxml.jackson.annotation.JsonProperty; +import net.dv8tion.jda.api.interactions.IntegrationOwners; +import net.dv8tion.jda.api.interactions.InteractionContextType; import org.togetherjava.tjbot.jda.payloads.PayloadChannel; +import org.togetherjava.tjbot.jda.payloads.PayloadGuild; import org.togetherjava.tjbot.jda.payloads.PayloadMember; public final class PayloadSlashCommand { @@ -16,11 +19,18 @@ public final class PayloadSlashCommand { private String token; private PayloadMember member; private PayloadChannel channel; + private PayloadGuild guild; private PayloadSlashCommandData data; + @JsonProperty("channel_id") + private long channelId; + private InteractionContextType context; + @JsonProperty("authorizing_integration_owners") + private IntegrationOwners integrationOwners; public PayloadSlashCommand(String guildId, String id, int type, int version, String applicationId, String token, PayloadMember member, PayloadChannel channel, - PayloadSlashCommandData data) { + PayloadGuild guild, PayloadSlashCommandData data, long channelId, + InteractionContextType context, IntegrationOwners integrationOwners) { this.guildId = guildId; this.id = id; this.type = type; @@ -29,7 +39,11 @@ public PayloadSlashCommand(String guildId, String id, int type, int version, this.token = token; this.member = member; this.channel = channel; + this.guild = guild; this.data = data; + this.channelId = channelId; + this.context = context; + this.integrationOwners = integrationOwners; } public String getGuildId() { @@ -96,6 +110,14 @@ public void setChannel(PayloadChannel channel) { this.channel = channel; } + public PayloadGuild getGuild() { + return guild; + } + + public void setGuild(PayloadGuild guild) { + this.guild = guild; + } + public PayloadSlashCommandData getData() { return data; } @@ -104,4 +126,28 @@ public void setData(PayloadSlashCommandData data) { this.data = data; } + public long getChannelId() { + return channelId; + } + + public void setChannelId(long channelId) { + this.channelId = channelId; + } + + public InteractionContextType getContext() { + return context; + } + + public void setContext(InteractionContextType context) { + this.context = context; + } + + public IntegrationOwners getIntegrationOwners() { + return integrationOwners; + } + + public void setIntegrationOwners(IntegrationOwners integrationOwners) { + this.integrationOwners = integrationOwners; + } + } diff --git a/build.gradle b/build.gradle index 3546b7a0b0..d0588c0496 100644 --- a/build.gradle +++ b/build.gradle @@ -1,17 +1,21 @@ plugins { id 'java' - id "com.diffplug.spotless" version "6.25.0" - id "org.sonarqube" version "6.0.1.5171" - id "name.remal.sonarlint" version "4.2.2" + id "com.diffplug.spotless" version "7.0.4" + id "org.sonarqube" version "6.2.0.5505" + id "name.remal.sonarlint" version "5.1.10" +} +repositories { + mavenCentral() } group 'org.togetherjava' version '1.0-SNAPSHOT' ext { - jooqVersion = '3.19.1' - jacksonVersion = '2.18.1' - chatGPTVersion = '0.18.0' + jooqVersion = '3.20.5' + jacksonVersion = '2.19.1' + chatGPTVersion = '0.18.2' + junitVersion = '5.13.2' } // Skips sonarlint during the build, useful for testing purposes. @@ -28,7 +32,7 @@ sonarqube { } // Install git hooks -task installLocalGitHook(type: Copy) { +tasks.register('installLocalGitHook', Copy) { from new File(rootProject.rootDir, 'scripts/pre-commit') into new File(rootProject.rootDir, '.git/hooks') fileMode 0775 @@ -55,7 +59,7 @@ subprojects { java { toolchain { // Nails the Java-Version of every Subproject - languageVersion = JavaLanguageVersion.of(21) + languageVersion = JavaLanguageVersion.of(24) } } @@ -63,7 +67,7 @@ subprojects { sonarLint { rules { disable( - 'java:S1135' // Disables "Track uses of "TO-DO" tags" rule. + 'java:S1135', // Disables "Track uses of "TO-DO" tags" rule. ) } } @@ -94,5 +98,4 @@ subprojects { compileTestJava { options.encoding = "UTF-8" } - } diff --git a/database/build.gradle b/database/build.gradle index 9ec27d228d..be4adf2b9d 100644 --- a/database/build.gradle +++ b/database/build.gradle @@ -2,12 +2,12 @@ plugins { id 'java' } -var sqliteVersion = "3.47.1.0" +var sqliteVersion = "3.50.1.0" dependencies { implementation 'com.google.code.findbugs:jsr305:3.0.2' implementation "org.xerial:sqlite-jdbc:${sqliteVersion}" - implementation 'org.flywaydb:flyway-core:11.1.0' + implementation 'org.flywaydb:flyway-core:11.10.0' implementation "org.jooq:jooq:$jooqVersion" implementation project(':utils') diff --git a/formatter/build.gradle b/formatter/build.gradle index 41344106fc..17c7329792 100644 --- a/formatter/build.gradle +++ b/formatter/build.gradle @@ -6,8 +6,9 @@ dependencies { implementation 'com.google.code.findbugs:jsr305:3.0.2' implementation project(':utils') - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.4' - testImplementation 'org.junit.jupiter:junit-jupiter-params:5.11.0' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.1' + testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" + testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion" + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd49177..1b33c55baa 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1af9e0930b..ff23a68d70 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a4269..23d15a9367 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -112,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -203,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. @@ -211,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 93e3f59f13..db3a6ac207 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,22 +59,22 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/settings.gradle b/settings.gradle index fcbfb6d3e2..ae0349509c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,5 @@ plugins { - id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' + id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' } rootProject.name = 'TJ-Bot'