Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
9c79487
fix(ci): declare the version input on publish-maven
THEROER Jul 4, 2026
4b3fd0f
refactor(build-logic): move plugins into dev.ua.theroer.magicutils.bu…
THEROER Jul 5, 2026
d2f0ba5
ci: publish aggregated themed Javadoc on release
THEROER Jul 6, 2026
2daad55
build: migrate to Kotlin DSL with a target matrix and consumer API
THEROER Jul 6, 2026
67d115b
build(build-logic): unify consumer embed modes across loaders
THEROER Jul 6, 2026
3b83055
feat(platform-bukkit): warn when MagicUtils is loaded more than once
THEROER Jul 6, 2026
9914157
feat(registry): serve /magicutils mods from a live consumer view
THEROER Jul 6, 2026
64f083a
refactor(logger): share MiniMessage attribute escaping, make /mu mods…
THEROER Jul 6, 2026
9c77615
build(build-logic): add a configurable buildAllTargets fan-out
THEROER Jul 6, 2026
5c4603d
feat(bukkit-bundle): ship as a Paper plugin serving live consumer pay…
THEROER Jul 6, 2026
bb69482
refactor(bootstrap): register Fabric/NeoForge consumers via the live …
THEROER Jul 6, 2026
7e3c428
build(build-logic): bundle http-client into the fabric bundle
THEROER Jul 6, 2026
41dd5bd
refactor(bukkit): register the consumer once now the registry is live
THEROER Jul 6, 2026
4abeeca
test(build-logic): update matrix/release/smoke tests for the current …
THEROER Jul 6, 2026
4c2c978
build(build-logic): bump plugins to 0.1.5 for the EmbedMode API
THEROER Jul 6, 2026
7750951
ci: stop double-caching Gradle across setup-java and setup-gradle
THEROER Jul 6, 2026
435eb66
build(build-logic): track the target source package hidden by gitignore
THEROER Jul 6, 2026
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
2 changes: 0 additions & 2 deletions .github/workflows/ci-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ jobs:
with:
distribution: 'temurin'
java-version: '25'
cache: 'gradle'
- uses: gradle/actions/setup-gradle@v3
- id: matrix
run: |
Expand All @@ -38,7 +37,6 @@ jobs:
with:
distribution: 'temurin'
java-version: '25'
cache: 'gradle'
- uses: gradle/actions/setup-gradle@v3
- run: chmod +x ./gradlew
- run: ./gradlew buildScenario checkScenario -Ptarget=${{ matrix.target }}
15 changes: 10 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,19 @@ jobs:
with:
distribution: 'temurin'
java-version: '25'
cache: 'gradle'
# Gradle caching is owned by setup-gradle alone. Letting setup-java also
# cache 'gradle' had both actions restore ~/.gradle, layering a stale
# Kotlin incremental/compiled-classes state from other branches over this
# checkout — which surfaced as bogus "unresolved reference"/type-mismatch
# errors in build-logic that never reproduce on a clean build.
- uses: gradle/actions/setup-gradle@v3
- run: chmod +x ./gradlew
# Run inside the included build so only build-logic is configured — running
# `:build-logic:test` from the root configures every module (incl. the
# Fabric/Loom ones), which needlessly fetches Minecraft and flakes on the
# Loom cache/checksum in CI.
- run: ./gradlew -p build-logic test
# Loom cache/checksum in CI. `clean` first so no cross-branch incremental
# Kotlin state is reused.
- run: ./gradlew -p build-logic clean test

# Single source of truth: the target list comes from targets.properties
# via printBuildMatrix — never hardcoded here.
Expand All @@ -39,7 +44,7 @@ jobs:
with:
distribution: 'temurin'
java-version: '25'
cache: 'gradle'
# Gradle caching is owned by setup-gradle alone (see build-logic-test).
- uses: gradle/actions/setup-gradle@v3
- id: matrix
run: |
Expand All @@ -59,7 +64,7 @@ jobs:
with:
distribution: 'temurin'
java-version: '25'
cache: 'gradle'
# Gradle caching is owned by setup-gradle alone (see build-logic-test).
- uses: gradle/actions/setup-gradle@v3
- run: chmod +x ./gradlew
- run: ./gradlew buildScenario checkScenario -Ptarget=${{ matrix.target }}
67 changes: 67 additions & 0 deletions .github/workflows/publish-javadoc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: publish-javadoc

on:
# Dispatched by release.yml after the tag is created (alongside publish-maven),
# and runnable manually. Generates the aggregated, themed Javadoc for the
# common modules and uploads it to the self-hosted Reposilite as a single zip
# at a stable, version-independent path. The docs site (MagicUtilsWebsite)
# downloads that zip during its Docker build and serves it under /javadoc.
workflow_dispatch:
inputs:
version:
description: "Release version being published (informational)"
required: false
default: ""

permissions:
contents: read

concurrency:
group: publish-javadoc
cancel-in-progress: true

jobs:
publish-javadoc:
runs-on: ubuntu-latest
env:
PUBLISH_USER: ${{ secrets.MAVEN_PUBLISH_USER }}
PUBLISH_TOKEN: ${{ secrets.MAVEN_PUBLISH_TOKEN }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.sha }}
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '25'
- uses: gradle/actions/setup-gradle@v3

- name: Generate aggregated Javadoc zip
run: |
chmod +x ./gradlew
./gradlew aggregatedJavadocZip

- name: Resolve upload URL
id: coords
run: |
REPO_URL=$(grep -E '^repo\.url=' gradle/publishing.properties | head -n1 | cut -d= -f2- | tr -d '[:space:]')
# Stable path: the docs build always fetches the latest published tree.
# A versioned copy is kept too, for reference/rollback.
echo "latest_url=${REPO_URL}/dev/ua/theroer/magicutils-javadoc/latest/magicutils-javadoc.zip" >> "$GITHUB_OUTPUT"
VERSION="${{ inputs.version }}"
if [ -n "$VERSION" ]; then
echo "version_url=${REPO_URL}/dev/ua/theroer/magicutils-javadoc/${VERSION}/magicutils-javadoc.zip" >> "$GITHUB_OUTPUT"
fi

- name: Upload to Reposilite
run: |
ZIP=build/docs/magicutils-javadoc.zip
test -f "$ZIP" || { echo "Javadoc zip not found at $ZIP"; exit 1; }
echo "Uploading to ${{ steps.coords.outputs.latest_url }}"
curl --fail-with-body -sS -u "$PUBLISH_USER:$PUBLISH_TOKEN" \
-T "$ZIP" "${{ steps.coords.outputs.latest_url }}"
if [ -n "${{ steps.coords.outputs.version_url }}" ]; then
echo "Uploading versioned copy to ${{ steps.coords.outputs.version_url }}"
curl --fail-with-body -sS -u "$PUBLISH_USER:$PUBLISH_TOKEN" \
-T "$ZIP" "${{ steps.coords.outputs.version_url }}"
fi
12 changes: 8 additions & 4 deletions .github/workflows/publish-maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,15 @@ name: publish-maven
on:
# Dispatched by release.yml after the tag is created (documentation moved to
# the separate MagicUtilsWebsite project, so there is no docs workflow to chain
# from anymore). Also runnable manually.
# from anymore). Also runnable manually. The version is resolved from the
# checked-out gradle.properties; the input exists only so release.yml can pass
# it through for traceability without a dispatch error.
workflow_dispatch:
inputs:
version:
description: "Release version being published (informational)"
required: false
default: ""

# Publishing targets the self-hosted Reposilite (maven.theroer.dev) over HTTPS,
# so no repository write access to this GitHub repo is needed anymore.
Expand Down Expand Up @@ -32,7 +39,6 @@ jobs:
with:
distribution: 'temurin'
java-version: '25'
cache: 'gradle'
- uses: gradle/actions/setup-gradle@v3
- id: matrix
run: |
Expand Down Expand Up @@ -65,7 +71,6 @@ jobs:
with:
distribution: 'temurin'
java-version: '25'
cache: 'gradle'
- uses: gradle/actions/setup-gradle@v3
- name: Publish ${{ matrix.unit.target }}
run: |
Expand All @@ -92,7 +97,6 @@ jobs:
with:
distribution: 'temurin'
java-version: '25'
cache: 'gradle'
- uses: gradle/actions/setup-gradle@v3
- name: Publish build-logic plugins
run: |
Expand Down
12 changes: 11 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ jobs:
with:
distribution: 'temurin'
java-version: '25'
cache: 'gradle'

- uses: gradle/actions/setup-gradle@v3

Expand Down Expand Up @@ -101,3 +100,14 @@ jobs:
gh workflow run publish-maven.yml --repo "$GITHUB_REPOSITORY" --ref "$TAG" \
-f version="$VERSION"
echo "Dispatched publish-maven.yml for $TAG"
- name: Dispatch Javadoc publish
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ needs.resolve.outputs.version }}"
TAG="${{ needs.resolve.outputs.tag }}"
# Aggregated, themed Javadoc for the common modules is generated and
# uploaded to Reposilite; the docs site pulls it in at Docker build time.
gh workflow run publish-javadoc.yml --repo "$GITHUB_REPOSITORY" --ref "$TAG" \
-f version="$VERSION"
echo "Dispatched publish-javadoc.yml for $TAG"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ venv/

# Maven (if used alongside Gradle)
target/
# but not the build-logic source package that happens to be named target/
!build-logic/src/main/kotlin/dev/ua/theroer/magicutils/build/target/
!build-logic/src/main/kotlin/dev/ua/theroer/magicutils/build/target/**
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
Expand Down
71 changes: 57 additions & 14 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,23 @@ dependencies {
implementation("fabric-loom:fabric-loom.gradle.plugin:${project.property("fabricLoomVersion")}")
implementation("net.fabricmc.fabric-loom:net.fabricmc.fabric-loom.gradle.plugin:${project.property("fabricLoomVersion")}")

// jpenilla run-* task plugins, applied by the consumer-* plugins only when a
// consumer opts into `devServer {}`. run-paper carries the Paper+Folia
// runners; run-velocity/run-waterfall carry the proxy runners. Applied via
// their plugin *marker* artifacts (same mechanism as Loom above) so
// `pluginManager.apply(id)` resolves them; their task types are configured
// by name, with no compile-time API import into build-logic.
val runPaperVersion = project.property("runPaperVersion")
val runProxyVersion = project.property("runProxyVersion")
implementation("xyz.jpenilla.run-paper:xyz.jpenilla.run-paper.gradle.plugin:$runPaperVersion")
implementation("xyz.jpenilla.run-velocity:xyz.jpenilla.run-velocity.gradle.plugin:$runPaperVersion")
implementation("xyz.jpenilla.run-waterfall:xyz.jpenilla.run-waterfall.gradle.plugin:$runProxyVersion")

// ModDevGradle marker, applied by consumer-neoforge via pluginManager.apply(id).
// Its API is not imported into build-logic; the neoForge extension is reached
// reflectively so only the marker (not moddev's types) is needed here.
implementation("net.neoforged.moddev:net.neoforged.moddev.gradle.plugin:${project.property("neoForgeModdevVersion")}")

testImplementation(platform("org.junit:junit-bom:5.11.3"))
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
Expand All @@ -82,59 +99,85 @@ gradlePlugin {
plugins {
register("magicutilsTarget") {
id = "magicutils.target"
implementationClass = "MagicUtilsTargetPlugin"
implementationClass = "dev.ua.theroer.magicutils.build.matrix.MagicUtilsTargetPlugin"
}
register("magicutilsMatrixSettings") {
id = "magicutils.matrix-settings"
implementationClass = "MagicUtilsMatrixSettingsPlugin"
implementationClass = "dev.ua.theroer.magicutils.build.matrix.MagicUtilsMatrixSettingsPlugin"
}
register("magicutilsMatrixRoot") {
id = "magicutils.matrix-root"
implementationClass = "MagicUtilsMatrixRootPlugin"
implementationClass = "dev.ua.theroer.magicutils.build.matrix.MagicUtilsMatrixRootPlugin"
}
register("magicutilsRepositories") {
id = "magicutils.repositories"
implementationClass = "MagicUtilsRepositoriesPlugin"
implementationClass = "dev.ua.theroer.magicutils.build.support.MagicUtilsRepositoriesPlugin"
}
register("magicutilsCommon") {
id = "magicutils.common"
implementationClass = "MagicUtilsCommonPlugin"
implementationClass = "dev.ua.theroer.magicutils.build.module.MagicUtilsCommonPlugin"
}
register("magicutilsJavaLibrary") {
id = "magicutils.java-library"
implementationClass = "MagicUtilsJavaLibraryPlugin"
implementationClass = "dev.ua.theroer.magicutils.build.module.MagicUtilsJavaLibraryPlugin"
}
register("magicutilsAnnotationProcessing") {
id = "magicutils.annotation-processing"
implementationClass = "MagicUtilsAnnotationProcessingPlugin"
implementationClass = "dev.ua.theroer.magicutils.build.module.MagicUtilsAnnotationProcessingPlugin"
}
register("magicutilsShadow") {
id = "magicutils.shadow"
implementationClass = "MagicUtilsShadowPlugin"
implementationClass = "dev.ua.theroer.magicutils.build.module.MagicUtilsShadowPlugin"
}
register("magicutilsShadedModule") {
id = "magicutils.shaded-module"
implementationClass = "MagicUtilsShadedModulePlugin"
implementationClass = "dev.ua.theroer.magicutils.build.module.MagicUtilsShadedModulePlugin"
}
register("magicutilsPublishing") {
id = "magicutils.publishing"
implementationClass = "MagicUtilsPublishingPlugin"
implementationClass = "dev.ua.theroer.magicutils.build.publish.MagicUtilsPublishingPlugin"
}
register("magicutilsFabricModule") {
id = "magicutils.fabric-module"
implementationClass = "MagicUtilsFabricModulePlugin"
implementationClass = "dev.ua.theroer.magicutils.build.module.MagicUtilsFabricModulePlugin"
}
register("magicutilsFabricBundle") {
id = "magicutils.fabric-bundle"
implementationClass = "MagicUtilsFabricBundlePlugin"
implementationClass = "dev.ua.theroer.magicutils.build.module.MagicUtilsFabricBundlePlugin"
}
register("magicutilsBukkitBundle") {
id = "magicutils.bukkit-bundle"
implementationClass = "MagicUtilsBukkitBundlePlugin"
implementationClass = "dev.ua.theroer.magicutils.build.module.MagicUtilsBukkitBundlePlugin"
}
// Consumer-facing plugins for downstream plugins/mods (not MagicUtils'
// own library modules): hide Loom/obf/classifier/toolchain selection.
register("magicutilsConsumerCommon") {
id = "magicutils.consumer-common"
implementationClass = "dev.ua.theroer.magicutils.build.consumer.MagicUtilsConsumerCommonPlugin"
}
register("magicutilsConsumerBukkit") {
id = "magicutils.consumer-bukkit"
implementationClass = "dev.ua.theroer.magicutils.build.consumer.MagicUtilsConsumerBukkitPlugin"
}
register("magicutilsConsumerFabric") {
id = "magicutils.consumer-fabric"
implementationClass = "dev.ua.theroer.magicutils.build.consumer.MagicUtilsConsumerFabricPlugin"
}
register("magicutilsConsumerVelocity") {
id = "magicutils.consumer-velocity"
implementationClass = "dev.ua.theroer.magicutils.build.consumer.MagicUtilsConsumerVelocityPlugin"
}
register("magicutilsConsumerBungee") {
id = "magicutils.consumer-bungee"
implementationClass = "dev.ua.theroer.magicutils.build.consumer.MagicUtilsConsumerBungeePlugin"
}
register("magicutilsConsumerNeoForge") {
id = "magicutils.consumer-neoforge"
implementationClass = "dev.ua.theroer.magicutils.build.consumer.MagicUtilsConsumerNeoForgePlugin"
}
register("magicutilsNeoForgeBundle") {
id = "magicutils.neoforge-bundle"
implementationClass = "MagicUtilsNeoForgeBundlePlugin"
implementationClass = "dev.ua.theroer.magicutils.build.module.MagicUtilsNeoForgeBundlePlugin"
}
}
}
10 changes: 9 additions & 1 deletion build-logic/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
shadowVersion=9.3.1
fabricLoomVersion=1.17.13

# jpenilla run-* task plugins, applied by the consumer-* plugins on devServer{}
# opt-in. run-paper/run-velocity share a version line; run-waterfall lags.
runPaperVersion=3.0.2
runProxyVersion=2.3.1

# ModDevGradle, applied by consumer-neoforge (moddev provides the NeoForge run).
neoForgeModdevVersion=2.0.139

# Coordinates for publishing the build-logic plugins as a reusable tool.
# Independent of the MagicUtils library version (root gradle.properties).
pluginsGroup=dev.ua.theroer.magicutils.build
pluginsVersion=0.1.0
pluginsVersion=0.1.5
Loading
Loading