Skip to content
Merged
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
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,3 @@ LICENSE
Dockerfile
*.dockerfile
Bumpfile
qodana.yaml
33 changes: 1 addition & 32 deletions .github/workflows/unit-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
uses: actions/setup-java@v6
with:
distribution: temurin
java-version: 26
java-version: 27

- name: Setup project and upload dependency graph
uses: gradle/actions/setup-gradle@v6
Expand All @@ -61,34 +61,3 @@ jobs:

- name: Execute tests
run: ./gradlew check

qodana:
name: Perform Qodana analysis
needs: tests
runs-on: ubuntu-latest
permissions:
checks: write
security-events: write
steps:
- name: Checkout code changes
uses: actions/checkout@v7
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0

- name: Execute analysis
uses: JetBrains/qodana-action@v2026.2.2
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
with:
use-caches: false
post-pr-comment: false
pr-mode: false
# bump: Qodana /qodana-jvm-community:([\d.]+)/ docker:jetbrains/qodana-jvm-community|/^[\d]{4}\.\d+$/|sort
args: --image jetbrains/qodana-jvm-community:2026.2

- name: Upload results to GitHub
if: ${{ !cancelled() }}
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,3 @@ buildNumber.properties
.idea/
src/main/resources/*.png
.gradle/
.qodana
1 change: 0 additions & 1 deletion Bumpfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
.github/workflows/unit-test.yml
Dockerfile
qodana.yaml
7 changes: 1 addition & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM eclipse-temurin:26-alpine AS builder
FROM eclipse-temurin:27-alpine AS builder

WORKDIR /app

Expand All @@ -10,17 +10,12 @@ RUN --mount=type=cache,target=/root/.gradle ./gradlew check installDist --no-dae

FROM alpine:3.24.2

# bump: OpenTelemetry /opentelemetry-java-instrumentation\/releases\/download\/v([\d.]+)/ git:https://github.com/open-telemetry/opentelemetry-java-instrumentation.git|/\d+\./|*
ADD https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v2.31.1/opentelemetry-javaagent.jar \
/app/opentelemetry-agent.jar

COPY --from=builder /usr/bin/ff* /usr/bin/
COPY --from=builder /app/build/install/Stickerify/ .

ENV OTEL_SDK_DISABLED=true
ENV OTEL_METRICS_EXPORTER=none
ENV OTEL_LOGS_EXPORTER=none
ENV OTEL_JAVAAGENT_LOGGING=none
ENV JAVA_TOOL_OPTIONS=-javaagent:/app/opentelemetry-agent.jar
ENV CONCURRENT_PROCESSES=5
CMD ["./bin/Stickerify"]
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ And it's done!

## How to set up the project

1. Install JDK 26 (or higher)
1. Install JDK 27 (or higher)
2. Clone the project and move into its folder
3. Run the command `./gradlew build -x test`
4. Import the project inside your IDE as a Gradle project
5. Ensure your IDE is correctly configured to use a Java 26 (or higher) JDK
5. Ensure your IDE is correctly configured to use a Java 27 (or higher) JDK

## How to run the bot locally

Expand Down
58 changes: 35 additions & 23 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import com.github.stickerifier.stickerify.DownloadOpenTelemetryAgentTask
import com.github.stickerifier.stickerify.JlinkJavaLauncher
import com.github.stickerifier.stickerify.JlinkTask
import com.github.stickerifier.stickerify.JunitSeedArgumentProvider
import io.spring.gradle.nullability.NullabilityOptions
import org.gradle.internal.buildconfiguration.DaemonJvmPropertiesConfigurator
import org.gradle.kotlin.dsl.support.serviceOf

plugins {
java
Expand Down Expand Up @@ -39,43 +39,44 @@ version = "2.0"
description = "Telegram bot to convert medias into the format required to be used as Telegram stickers"

java.toolchain {
languageVersion = JavaLanguageVersion.of(26)
languageVersion = JavaLanguageVersion.of(27)
vendor = JvmVendorSpec.ADOPTIUM
}

tasks.named<UpdateDaemonJvm>(DaemonJvmPropertiesConfigurator.TASK_NAME) {
languageVersion = JavaLanguageVersion.of(26)
languageVersion = JavaLanguageVersion.of(27)
vendor = JvmVendorSpec.ADOPTIUM
}

val jlink = tasks.register<JlinkTask>("jlink") {
val jlink = tasks.register<JlinkTask>(JlinkTask.DEFAULT_TASK_NAME) {
description = "Generates a minimal JRE for the project with compact object headers archive."

options = listOf("--strip-debug", "--no-header-files", "--no-man-pages", "--ignore-modified-runtime")
options = listOf("--strip-debug", "--no-header-files", "--no-man-pages", "--ignore-modified-runtime", "--generate-cds-archive")
modules = listOf(
"java.instrument", // for JUnit
"java.naming", // for Logback
"java.management", // for OpenTelemetry
"java.sql", // for Tika
"jdk.unsupported" // for Gson
"java.instrument", // for JUnit
"java.management", // for OpenTelemetry
"java.naming", // for Logback
"java.sql", // for Tika
"jdk.unsupported" // for Gson
)
includeModulePath = false
javaCompiler = javaToolchains.compilerFor(java.toolchain)
}

val execOps = serviceOf<ExecOperations>()
doLast {
val javaExe = outputDirectory.file("jre/bin/java").get().asFile.absolutePath
execOps.exec {
commandLine(javaExe, "-XX:+UseCompactObjectHeaders", "-Xshare:dump")
}
nullability {
jspecify {
experimental = true
}
}

val CompileOptions.nullability: NullabilityOptions
get() = (this as ExtensionAware).extensions["nullability"] as NullabilityOptions
get() = (this as ExtensionAware).extensions.getByName("nullability") as NullabilityOptions

tasks.named<JavaCompile>(JavaPlugin.COMPILE_TEST_JAVA_TASK_NAME) {
options.nullability.checking = "tests"
options.nullability.jspecify {
experimental = true
}
}

tasks.test {
Expand All @@ -99,18 +100,29 @@ tasks.test {

application {
mainClass = "com.github.stickerifier.stickerify.runner.Main"
applicationDefaultJvmArgs = listOf("-XX:+UseCompactObjectHeaders", "-XX:+UseShenandoahGC", "-XX:ShenandoahGCMode=generational", "--enable-final-field-mutation=ALL-UNNAMED")
applicationDefaultJvmArgs = listOf("--enable-final-field-mutation=ALL-UNNAMED")
}

val openTelemetryAgent = tasks.register<DownloadOpenTelemetryAgentTask>(DownloadOpenTelemetryAgentTask.DEFAULT_TASK_NAME) {
description = "Downloads the OpenTelemetry agent for the distribution package."
Comment thread
rob93c marked this conversation as resolved.

version = libs.versions.opentelemetry.get()
destinationFile = layout.buildDirectory.file("openTelemetryAgent/opentelemetry-javaagent.jar")
}

tasks.named<CreateStartScripts>(ApplicationPlugin.TASK_START_SCRIPTS_NAME) {
val agentJarName = openTelemetryAgent.get().destinationFile.get().asFile.name
defaultJvmOpts = (defaultJvmOpts ?: emptyList()) + "-javaagent:$agentJarName"

(unixStartScriptGenerator as TemplateBasedScriptGenerator).template = resources.text.fromFile("src/main/resources/customUnixStartScript.txt")
(windowsStartScriptGenerator as TemplateBasedScriptGenerator).template = resources.text.fromFile("src/main/resources/customWindowsStartScript.txt")
}

distributions {
main {
contents {
from(jlink)
from(openTelemetryAgent)
}
}
}

tasks.named<CreateStartScripts>(ApplicationPlugin.TASK_START_SCRIPTS_NAME) {
(unixStartScriptGenerator as TemplateBasedScriptGenerator).template = resources.text.fromFile("src/main/resources/customUnixStartScript.txt")
(windowsStartScriptGenerator as TemplateBasedScriptGenerator).template = resources.text.fromFile("src/main/resources/customWindowsStartScript.txt")
}
2 changes: 1 addition & 1 deletion buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ repositories {
}

java.toolchain {
languageVersion = JavaLanguageVersion.of(26)
languageVersion = JavaLanguageVersion.of(27)
vendor = JvmVendorSpec.ADOPTIUM
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.github.stickerifier.stickerify;

import org.gradle.api.DefaultTask;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import org.jetbrains.annotations.NotNull;

import javax.inject.Inject;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;

public abstract class DownloadOpenTelemetryAgentTask extends DefaultTask {

public static final String DEFAULT_TASK_NAME = "downloadOpenTelemetryAgent";

@Input
public abstract Property<@NotNull String> getVersion();

@Input
public abstract Property<@NotNull Integer> getDownloadTimeoutMillis();

@OutputFile
public abstract RegularFileProperty getDestinationFile();

@Inject
public DownloadOpenTelemetryAgentTask() {
setGroup("distribution");
setDescription("Downloads OpenTelemetry agent jar.");

getDownloadTimeoutMillis().convention(12000);
}

@TaskAction
public void downloadJar() throws IOException {
var version = getVersion().get();
var urlString = "https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v%s/opentelemetry-javaagent.jar".formatted(version);
var targetFile = getDestinationFile().get().getAsFile();

var _ = targetFile.getParentFile().mkdirs();

var connection = URI.create(urlString).toURL().openConnection();
int timeoutMillis = getDownloadTimeoutMillis().get();
connection.setConnectTimeout(timeoutMillis);
connection.setReadTimeout(timeoutMillis);

try (var inputStream = connection.getInputStream()) {
Files.copy(inputStream, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

public abstract class JlinkTask extends DefaultTask {

public static final String DEFAULT_TASK_NAME = "jlink";

@Input
public abstract ListProperty<@NotNull String> getOptions();

Expand Down
21 changes: 10 additions & 11 deletions gradle/gradle-daemon-jvm.properties
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
#This file is generated by updateDaemonJvm
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/39e8ce74cee3e629d6fade20d237fff5/redirect
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/b7f6da648647bf05d05a14cdca409f73/redirect
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/39e8ce74cee3e629d6fade20d237fff5/redirect
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/b7f6da648647bf05d05a14cdca409f73/redirect
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/b5e76458e870841069679392d5855834/redirect
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/ef59bf670a5688da71dc8f2e9d1f8b76/redirect
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/39e8ce74cee3e629d6fade20d237fff5/redirect
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/b7f6da648647bf05d05a14cdca409f73/redirect
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/06340fb34ff0b1b2e0cde9562b75744e/redirect
#This file is generated by :updateDaemonJvm
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/22fd4fd9a5dedf12964be0a987f4e90b/redirect
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/c753409d258f3e09db9cfda022a8b52a/redirect
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/22fd4fd9a5dedf12964be0a987f4e90b/redirect
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/c753409d258f3e09db9cfda022a8b52a/redirect
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/7857181a003a2064a9272111de852844/redirect
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/22fd4fd9a5dedf12964be0a987f4e90b/redirect
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/c753409d258f3e09db9cfda022a8b52a/redirect
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/36c6fff412e42f23a647ccc8ac1ee8fe/redirect
toolchainVendor=ADOPTIUM
toolchainVersion=26
toolchainVersion=27
3 changes: 2 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[versions]
junit = "6.1.3"
opentelemetry = "2.32.0"

[libraries]
gson = "com.google.code.gson:gson:2.14.0"
Expand All @@ -11,7 +12,7 @@ junit-platform = { module = "org.junit.platform:junit-platform-launcher", versio
logback-classic = "ch.qos.logback:logback-classic:1.6.5"
logstash-logback-encoder = "net.logstash.logback:logstash-logback-encoder:9.0"
mockwebserver = "com.squareup.okhttp3:mockwebserver3-junit5:5.5.0"
opentelemetry-instrumentation-annotations = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations:2.31.1"
opentelemetry-instrumentation-annotations = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations", version.ref = "opentelemetry" }
telegram-bot-api = "com.github.pengrad:java-telegram-bot-api:10.3.0"
tika = "org.apache.tika:tika-core:4.1.0"

Expand Down
8 changes: 0 additions & 8 deletions qodana.yaml

This file was deleted.

Comment thread
MartelliEnrico marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import com.pengrad.telegrambot.request.richmessages.SendRichMessage;
import com.pengrad.telegrambot.request.richmessages.SendRichMessageDraft;
import com.pengrad.telegrambot.response.BaseResponse;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.instrumentation.annotations.WithSpan;
import org.jspecify.annotations.Nullable;
import org.slf4j.event.Level;
Expand All @@ -57,7 +58,7 @@
public record Stickerify(TelegramBot bot, Executor executor) implements UpdatesListener, ExceptionHandler, AutoCloseable {

private static final StructuredLogger LOGGER = new StructuredLogger(Stickerify.class);
private static final String BOT_TOKEN = System.getenv("STICKERIFY_TOKEN");
private static final @Nullable String BOT_TOKEN = System.getenv("STICKERIFY_TOKEN");
private static final ThreadFactory VIRTUAL_THREAD_FACTORY = Thread.ofVirtual().name("Virtual-", 0).factory();
private static final InputRichMessage PROCESSING_MESSAGE = new InputRichMessage().html(PROCESSING.getText());

Expand Down Expand Up @@ -107,7 +108,7 @@ public void close() {
bot.shutdown();
}

@WithSpan("bot.answer")
@WithSpan(value = "bot.answer", kind = SpanKind.CONSUMER)
private void answer(TelegramRequest request) {
LOGGER.at(Level.INFO).log("Received request");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ private static File convertToWebm(File file) throws MediaException, InterruptedE
"-c:v", "libvpx-" + VP9_CODEC,
"-row-mt", "1",
"-threads", "2",
"-filter_threads", "1",
Comment thread
rob93c marked this conversation as resolved.
"-g", "120",
"-auto-alt-ref", "0",
"-pix_fmt", "yuv420p",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.github.stickerifier.stickerify.process;

import static java.util.Objects.requireNonNullElse;

public final class OsConstants {
private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("windows");
private static final boolean IS_WINDOWS = requireNonNullElse(System.getProperty("os.name"), "").toLowerCase().contains("windows");

public static final String NULL_FILE = IS_WINDOWS ? "NUL" : "/dev/null";

Expand Down
Loading
Loading