Skip to content
Closed
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
54 changes: 4 additions & 50 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,55 +1,9 @@
# Automatically build the project and run any configured tests for every push
# and submitted pull request. This can help catch issues that only occur on
# certain platforms or Java versions, and provides a first line of defence
# against bad commits.

name: build
on: [pull_request, push]

permissions:
contents: read

jobs:
build:
strategy:
matrix:
java: [
25,
]

distribution: [
"temurin",
]

os: [ubuntu-24.04]

runs-on: ${{ matrix.os }}
steps:
- name: checkout repository
uses: actions/checkout@v6
- name: validate gradle wrapper
uses: gradle/actions/wrapper-validation@v5
- name: setup jdk ${{ matrix.java }}
uses: actions/setup-java@v5
with:
java-version: ${{ matrix.java }}
distribution: ${{ matrix.distribution }}
cache: 'gradle'
- name: make gradle wrapper executable
run: chmod +x ./gradlew
- name: cache gradle
uses: actions/cache@v5
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
~/.gradle/build-cache
~/.gradle/daemon
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
${{ runner.os }}-
- name: build
run: ./gradlew chiseledBuild --build-cache --no-configuration-cache
- name: capture build artifacts
uses: actions/upload-artifact@v6
with:
name: Artifacts
path: build/libs/
uses: ./.github/workflows/build_reusable.yml
58 changes: 58 additions & 0 deletions .github/workflows/build_reusable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: build (reusable)

on:
workflow_call:
inputs:
publish:
description: Also upload every target to Modrinth and CurseForge.
type: boolean
default: false
secrets:
MODRINTH_API_KEY:
required: false
CURSEFORGE_TOKEN:
required: false

jobs:
build:
runs-on: ubuntu-24.04
steps:
- name: checkout repository
uses: actions/checkout@v6

- name: validate gradle wrapper
uses: gradle/actions/wrapper-validation@v5
# One JDK for everything: the buildscripts pin a Java 25 toolchain and set
# options.release per target, so javac emits the right bytecode level (8 for
# 1.16.5, 17 for 1.18-1.20.4, ...) without a JDK per Minecraft version.
- name: setup jdk
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 25

- name: setup gradle
uses: gradle/actions/setup-gradle@v4

- name: make gradle wrapper executable
run: chmod +x ./gradlew

- name: build all targets
run: ./gradlew chiseledBuild --continue --stacktrace --build-cache --no-configuration-cache

# -PpublishRelease is what flips publishMods out of dry-run mode. Without this step
# (or without that flag) nothing is ever uploaded.
- name: publish all targets
if: inputs.publish
env:
MODRINTH_API_KEY: ${{ secrets.MODRINTH_API_KEY }}
CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }}
run: ./gradlew chiseledPublish -PpublishRelease --stacktrace --build-cache --no-configuration-cache

- name: capture build artifacts
if: always()
uses: actions/upload-artifact@v6
with:
name: xyzcopy-jars
path: build/libs/**/*.jar
if-no-files-found: warn
49 changes: 49 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Tag-triggered release: verifies the tag matches mod.version, builds every target and
# uploads them to Modrinth/CurseForge. The jars are also kept as workflow artifacts.
#
# Requires two repository secrets: MODRINTH_API_KEY and CURSEFORGE_TOKEN.
# Tag either `1.0.0` or `v1.0.0` — both are accepted as long as the number matches
# mod.version in stonecutter.properties.toml.

name: release

on:
push:
tags:
- '*'

permissions:
contents: read

jobs:
validate:
name: validate tag
runs-on: ubuntu-24.04
steps:
- name: checkout repository
uses: actions/checkout@v6

# Guards against tagging a commit whose mod.version was never bumped, which would
# otherwise publish a release under the previous version number.
- name: check tag matches mod.version
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME#v}"
version="$(sed -n 's/^mod\.version[[:space:]]*=[[:space:]]*"\(.*\)"/\1/p' stonecutter.properties.toml)"
if [ -z "$version" ]; then
echo "::error::could not read mod.version from stonecutter.properties.toml"
exit 1
fi
if [ "$tag" != "$version" ]; then
echo "::error::tag '${GITHUB_REF_NAME}' does not match mod.version '${version}'"
exit 1
fi
echo "tag '${GITHUB_REF_NAME}' matches mod.version '${version}'"

publish:
name: build and publish
needs: validate
uses: ./.github/workflows/build_reusable.yml
with:
publish: true
secrets: inherit
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# shhhh ai
.ai
.claude
.codex

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Expand Down Expand Up @@ -95,4 +100,7 @@ run/
# architectury

.architectury-transformer\debug.log
.architectury-transformer/debug.log
.architectury-transformer/debug.log

# superpowers
docs/superpowers/
1 change: 1 addition & 0 deletions .sc_active_version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
26.1-fabric
2 changes: 1 addition & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
changes:
- initial release
- 26.x support
135 changes: 135 additions & 0 deletions build.fabric.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import dev.kikugie.stonecutter.data.deserialization.SCList
import dev.kikugie.stonecutter.data.deserialization.SCPrimitive
import me.modmuss50.mpp.ReleaseType

plugins {
id("loom-plugin-chooser")
alias(libs.plugins.mod.publish)
}

val modVersion = property("mod.version") as String
val modId = property("mod.id") as String
val mcCompat = property("mod.mc_compat") as String
val versionName = property("mod.version_name") as String
val obfuscated = sc.current.version.startsWith("1.")
val keyBindingApi = if (sc.current.parsed >= "26.1") "fabric-key-mapping-api-v1" else "fabric-key-binding-api-v1"

version = "$modVersion+$versionName-fabric"
group = property("mod.group") as String
base.archivesName = modId

val requiredJava: JavaVersion = when {
sc.current.parsed >= "26.1" -> JavaVersion.VERSION_25
sc.current.parsed >= "1.20.5" -> JavaVersion.VERSION_21
sc.current.parsed >= "1.18" -> JavaVersion.VERSION_17
sc.current.parsed >= "1.17" -> JavaVersion.VERSION_16
else -> JavaVersion.VERSION_1_8
}

repositories {
maven("https://maven.shedaniel.me/")
maven("https://maven.terraformersmc.com/releases/")
}

dependencies {
minecraft("com.mojang:minecraft:${sc.current.version}")
if (obfuscated) mappings(loom.officialMojangMappings())

modImplementation("net.fabricmc:fabric-loader:${property("deps.fabric_loader")}")
modImplementation("me.shedaniel.cloth:cloth-config-fabric:${property("deps.cloth_config")}")
modImplementation("com.terraformersmc:modmenu:${property("deps.mod_menu")}")
modImplementation("net.fabricmc.fabric-api:fabric-api:${property("deps.fabric_api")}")
}

loom {
runConfigs.all {
generateRunConfig = true
runDirectory = rootProject.layout.projectDirectory.dir("run")
}
decompilers {
get("vineflower").apply { options.put("mark-corresponding-synthetics", "1") }
}
}

java {
withSourcesJar()
toolchain {
vendor = JvmVendorSpec.ADOPTIUM
languageVersion = JavaLanguageVersion.of(25)
}
}

tasks.withType<JavaCompile>().configureEach {
options.release = requiredJava.majorVersion.toInt()
}

val runLauncher = extensions.getByType<JavaToolchainService>().launcherFor {
languageVersion = JavaLanguageVersion.of(requiredJava.majorVersion)
vendor = JvmVendorSpec.ADOPTIUM
}
tasks.withType<JavaExec>().matching { it.name.startsWith("run") }.configureEach {
javaLauncher = runLauncher
}

val mainJar = tasks.named(if (obfuscated) "remapJar" else "jar")
val srcJar = tasks.named(if (obfuscated) "remapSourcesJar" else "sourcesJar")

tasks {
processResources {
val mixinJava = "JAVA_${requiredJava.majorVersion}"
val props = mapOf("version" to modVersion, "minecraftVersion" to mcCompat, "javaVersion" to requiredJava.majorVersion, "keyBindingApi" to keyBindingApi)
props.forEach { (k, v) -> inputs.property(k, v) }
filesMatching("fabric.mod.json") { expand(props) }
filesMatching("*.mixins.json") { expand("java" to mixinJava) }
exclude("META-INF/mods.toml", "META-INF/neoforge.mods.toml", "pack.mcmeta")
}
register<Copy>("buildAndCollect") {
group = "build"
from(mainJar, srcJar)
into(rootProject.layout.buildDirectory.file("libs/$modVersion/fabric"))
}
}

val modrinthToken = providers.environmentVariable("MODRINTH_API_KEY")
.orElse(providers.systemProperty("MODRINTH_API_KEY"))
val curseforgeToken = providers.environmentVariable("CURSEFORGE_TOKEN")
.orElse(providers.systemProperty("CURSEFORGE_TOKEN"))

val mcReleases = (sc.properties.raw("mod", "mc_releases") as SCList)
.map { (it as SCPrimitive).content.toString() }

publishMods {
file = tasks.named<AbstractArchiveTask>(if (obfuscated) "remapJar" else "jar")
.flatMap { it.archiveFile }
type = ReleaseType.STABLE
displayName = "Fabric | $versionName [v$modVersion]"
version = project.version.toString()
changelog = "## [Fabric API](https://modrinth.com/mod/fabric-api) is required for Custom Keybinds!\n\n" +
rootProject.file("CHANGES.md").readText()
modLoaders.add("fabric")
modLoaders.add("quilt")

dryRun = !project.hasProperty("publishRelease")

modrinth {
accessToken = modrinthToken
projectId = "w4Xqquyv"
minecraftVersions.addAll(mcReleases)
requires("cloth-config")
optional("fabric-api")
optional("modmenu")
}

curseforge {
accessToken = curseforgeToken
projectId = "1421731"
minecraftVersions.addAll(mcReleases)
javaVersions.add(requiredJava)
client = true
server = false
changelogType = "markdown"
requires("cloth-config")
optional("fabric-api")
optional("modmenu")
}
}
Loading
Loading