feat: Wire Gradle for releasing

This commit is contained in:
Ampflower 🌺 2025-03-12 19:38:25 -07:00
parent 32d42939ed
commit a947c8a21a
No known key found for this signature in database
GPG Key ID: FC0397C90D508D7F
14 changed files with 488 additions and 8 deletions

View File

@ -5,20 +5,21 @@ import javax.imageio.ImageIO
plugins {
java
id("gay.ampflower.BuildPlugin")
alias(libs.plugins.loom)
alias(libs.plugins.minotaur)
}
val id: String by project
val excluded = setOf(rootProject, project(":xplat"))
allprojects {
apply(plugin = "java")
apply(plugin = "gay.ampflower.BuildPlugin")
apply(plugin = rootProject.libs.plugins.loom.get().pluginId)
apply(plugin = rootProject.libs.plugins.minotaur.get().pluginId)
val libs = rootProject.libs
version = meta.globalVersion
base {
if (project != rootProject) {
@ -90,10 +91,11 @@ allprojects {
}
val map = mapOf(
"id" to id,
"id" to mod.id.get(),
"version" to version,
"java" to java.targetCompatibility.majorVersion,
"loader" to libs.versions.fabric.loader.get(),
"description" to project.description,
"minecraftRequired" to libs.versions.minecraft.required.get(),
)

12
buildSrc/build.gradle.kts Normal file
View File

@ -0,0 +1,12 @@
plugins {
`java-gradle-plugin`
}
gradlePlugin {
plugins {
create("buildPlugin") {
id = "gay.ampflower.BuildPlugin"
implementationClass = "gay.ampflower.BuildPlugin"
}
}
}

View File

@ -0,0 +1,51 @@
package gay.ampflower;
import gay.ampflower.internal.Env;
import gay.ampflower.internal.Properties;
import gay.ampflower.internal.Util;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.VersionCatalogsExtension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Ampflower
* @since 0.0.0
**/
public class BuildPlugin implements Plugin<Project> {
private static final Logger logger = LoggerFactory.getLogger(BuildPlugin.class);
@Override
public void apply(final Project target) {
final var extensions = target.getExtensions();
if (extensions.findByType(Meta.class) != null) {
logger.warn("Meta already registered in {}, bailing", target);
return;
}
final var libs = target.getRootProject().getExtensions().getByType(VersionCatalogsExtension.class).named("libs");
final var version = Properties.str(target, "version");
final var minecraftVersion = libs.findLibrary("minecraft").get().get().getVersionConstraint().getRequiredVersion();
extensions.add("ci", new CiStatus(
Env.Publish,
Env.Release,
Env.Actions
));
extensions.add("meta", new Meta(
version,
Util.mkVersion(version + "+mc." + minecraftVersion),
Util.getVersionType(version),
Util.mkChangelog(Properties.str(target, "github")),
Util.getCompatibleVersions(libs, target)
));
extensions.add("mod", ModExtension.class);
logger.info("Got {}", extensions.findByName("meta"));
}
}

View File

@ -0,0 +1,12 @@
package gay.ampflower;
/**
* @author Ampflower
* @since 0.0.0
**/
public record CiStatus(
boolean publish,
boolean release,
boolean actions
) {
}

View File

@ -0,0 +1,20 @@
package gay.ampflower;
/**
* @author Ampflower
* @since 0.0.0
**/
public enum Environment {
ANY("*", "*", "BOTH"),
CLIENT("client", "client", "CLIENT"),
SERVER("server", "dedicated_server", "SERVER"),
;
public final String fabric, quilt, forge;
Environment(String fabric, String quilt, String forge) {
this.fabric = fabric;
this.quilt = quilt;
this.forge = forge;
}
}

View File

@ -0,0 +1,16 @@
package gay.ampflower;
import java.util.List;
/**
* @author Ampflower
* @since 0.0.0
**/
public record Meta(
String projectVersion,
String globalVersion,
String releaseType,
String changelog,
List<String> minecraftCompatible
) {
}

View File

@ -0,0 +1,73 @@
package gay.ampflower;
import org.gradle.api.Project;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
/**
* @author Ampflower
* @since 0.0.0
**/
public class ModExtension {
private final Property<String> id, version, name, description, icon;
private final Property<Environment> environment;
private final ListProperty<String> authors, licenses;
private final MapProperty<String, String> contact;
//private final Map<String, List<String>> entrypoints;
public ModExtension(Project project) {
final var rootProject = project.getRootProject();
final var objectFactory = project.getObjects();
this.id = objectFactory.property(String.class).convention(rootProject.getName());
this.version = objectFactory.property(String.class).convention((String) project.getVersion());
this.name = objectFactory.property(String.class).convention(rootProject.getDisplayName());
this.description = objectFactory.property(String.class).convention(rootProject.getDescription());
this.authors = objectFactory.listProperty(String.class);
this.contact = objectFactory.mapProperty(String.class, String.class);
this.licenses = objectFactory.listProperty(String.class);
this.icon = objectFactory.property(String.class);
this.environment = objectFactory.property(Environment.class);
}
public Property<String> getId() {
return this.id;
}
public Property<String> getVersion() {
return this.version;
}
public Property<String> getName() {
return this.name;
}
public Property<String> getDescription() {
return this.description;
}
public ListProperty<String> getAuthors() {
return this.authors;
}
public MapProperty<String, String> getContact() {
return this.contact;
}
public ListProperty<String> getLicenses() {
return this.licenses;
}
public Property<String> getIcon() {
return this.icon;
}
public Property<Environment> getEnvironment() {
return this.environment;
}
//public void depend(String dependency, Action<>)
}

View File

@ -0,0 +1,77 @@
package gay.ampflower.internal;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Ampflower
* @since 0.0.0
**/
public final class Env {
public static final boolean Publish = "release".equals(env("GITHUB_EVENT_NAME"));
public static final boolean Release = bool("BUILD_RELEASE");
public static final boolean Actions = bool("GITHUB_ACTIONS");
public static final @Nullable String Commit = env("GITHUB_SHA");
public static final @Nullable String RunNumber = env("GITHUB_RUN_NUMBER");
public static final @Nullable String Reference = env("GITHUB_REF");
public static final @Nullable String Changelog = env("CHANGELOG");
public static final @Nullable String ReleaseOverride = env("RELEASE_OVERRIDE");
private Env() {
}
public static boolean isReferenceTag() {
return Util.startsWith(Reference, "refs/tags/");
}
public static boolean isReferenceBranch() {
return Util.startsWith(Reference, "refs/heads/");
}
public static @Nullable String getTag() {
if (isReferenceTag()) {
return Reference.substring(10);
}
return null;
}
public static @Nullable String getBranch() {
if (isReferenceBranch()) {
return Reference.substring(11);
}
return null;
}
public static String getCommit(int limit) {
if (Commit == null) {
return "unknown";
}
if (limit > 0) {
return Commit.substring(0, Math.min(Commit.length(), limit));
}
return Commit;
}
public static String getRunNumber() {
if (RunNumber == null) {
return "unknown";
}
return RunNumber;
}
public static String getReference() {
if (Reference == null) {
return "unknown";
}
return Reference;
}
public static @Nullable String env(@NotNull String env) {
return System.getenv(env);
}
public static boolean bool(@NotNull String env) {
return Boolean.parseBoolean(env(env));
}
}

View File

@ -0,0 +1,40 @@
package gay.ampflower.internal;
import org.gradle.api.Project;
import org.jetbrains.annotations.Nullable;
/**
* @author Ampflower
* @since 0.0.0
**/
public final class Properties {
private static final String pluginStr = "gay.ampflower.";
public static boolean bool(Project project, String property) {
final var p = project.property(property);
if (p instanceof Boolean bool) {
return bool;
}
if (p instanceof String str) {
return Boolean.parseBoolean(str);
}
return false;
}
public static @Nullable String str(Project project, String property) {
final var p = project.property(property);
if (p == null) {
return null;
}
return p.toString();
}
public static boolean pluginBool(Project project, String property) {
return bool(project, pluginStr + property);
}
public static @Nullable String pluginStr(Project project, String property) {
return str(project, pluginStr + property);
}
}

View File

@ -0,0 +1,140 @@
package gay.ampflower.internal;
import org.gradle.api.Project;
import org.gradle.api.artifacts.VersionCatalog;
import org.gradle.api.artifacts.VersionConstraint;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;
/**
* @author Ampflower
* @since 0.0.0
**/
public class Util {
private static final Logger logger = LoggerFactory.getLogger(Util.class);
public static String urlEncode(String str) {
return URLEncoder.encode(str, StandardCharsets.UTF_8);
}
public static String mkChangelog(String git) {
if (!isBlank(Env.Changelog)) {
logger.debug("Changelog found, returning {}", Env.Changelog);
return Env.Changelog;
}
if (git == null) {
logger.warn("Git repository not defined. Returning null.");
return null;
}
if (startsWith(Env.Reference, "refs/tags/")) {
final var host = VcsHost.find(git);
logger.warn("Changelog not found but tag reference was, returning link to {}{}{}",
git, host.release, urlEncode(Env.getTag()));
return "You may view the changelog at " + git + host.release + urlEncode(Env.getTag());
}
logger.warn("Changelog and reference not found, returning link to {}", git);
return "No changelog is available. Perhaps poke at " + git + " for a changelog?";
}
public static String mkVersion(final String baseVersion) {
if (Env.Publish) {
return baseVersion;
}
if (Env.Actions) {
return baseVersion + "-build." + Env.getRunNumber() + "-commit." + Env.getCommit(7) + "-branch." + getBranchForVersion();
}
return baseVersion + "-build.local";
}
private static String getBranchForVersion() {
final var ref = Env.getBranch();
if (ref == null) {
return "unknown";
}
return ref.replace('/', '.');
}
public static List<String> getCompatibleVersions(VersionCatalog catalog, Project module) {
Optional<VersionConstraint> version;
switch (module.getName().toLowerCase()) {
case "neoforge":
version = catalog.findVersion("minecraft-neoforge-compatible");
logger.info("Testing Neoforge: {}", version);
if (version.isPresent()) break;
case "forge":
version = catalog.findVersion("minecraft-forge-compatible");
logger.info("Testing Forge: {}", version);
if (version.isPresent()) break;
case "quilt":
version = catalog.findVersion("minecraft-quilt-compatible");
logger.info("Testing Quilt: {}", version);
if (version.isPresent()) break;
case "fabric":
version = catalog.findVersion("minecraft-fabric-compatible");
logger.info("Testing Fabric: {}", version);
if (version.isPresent()) break;
default:
version = catalog.findVersion("minecraft-compatible");
logger.info("Testing default: {}", version);
}
if (version.isEmpty()) {
final var minecraft = catalog.findLibrary("minecraft").map(provider -> provider.get().getVersion());
if (minecraft.isPresent()) {
logger.warn("No marked compatible versions available for {}; compatible version will be marked as {}.",
module, minecraft.get());
return List.of(minecraft.get());
}
logger.warn("No marked compatible versions available for {}; compatible versions will not be marked.", module);
return List.of();
}
return List.of(version.get().getRequiredVersion().split(","));
}
public static String getVersionType(String version) {
if (!Util.isBlank(Env.ReleaseOverride)) {
return Env.ReleaseOverride;
}
if (version.contains("alpha")) {
return "alpha";
}
if (!Env.Release || version.indexOf('-') >= 0) {
return "beta";
}
return "release";
}
public static boolean isBlank(@Nullable String str) {
if (str == null) {
return true;
}
return str.isBlank();
}
public static boolean startsWith(@Nullable String str, @NotNull String prefix) {
if (str == null) {
return false;
}
return str.startsWith(prefix);
}
}

View File

@ -0,0 +1,33 @@
package gay.ampflower.internal;
/**
* @author Ampflower
* @since 0.0.0
**/
public enum VcsHost {
GitHub("github.com", "/issues", "/releases/tag/"),
GitLab("gitlab.com", "/-/issues", "/-/releases/"),
Codeberg("codeberg.org", "/issues", "/releases/tag/");
public final String host, issues, release;
VcsHost(String host, String issues, String release) {
this.host = host;
this.issues = issues;
this.release = release;
}
public static VcsHost find(String url) {
// "https://".length = 8
final int lastSlash = url.indexOf('/', 8);
for (final var host : values()) {
final var str = host.host;
final var len = str.length();
if (len > lastSlash) continue;
if (url.regionMatches(lastSlash - len, str, 0, len)) {
return host;
}
}
return null;
}
}

View File

@ -40,13 +40,13 @@ tasks {
modrinth {
token.set(System.getenv("MODRINTH_TOKEN"))
projectId.set(modrinthId)
//versionType.set(meta.releaseType)
//versionName.set("${meta.projectVersion} - Fabric ${libs.versions.minecraft.version.get()}")
versionType.set(meta.releaseType)
versionName.set("${meta.projectVersion} - Fabric ${libs.versions.minecraft.version.get()}")
versionNumber.set("${project.version}-fabric")
//changelog.set(meta.changelog)
changelog.set(meta.changelog)
uploadFile.set(tasks.remapJar)
dependencies {
}
//gameVersions.set(meta.minecraftCompatible)
gameVersions.set(meta.minecraftCompatible)
loaders.addAll("fabric", "quilt")
}

View File

@ -3,7 +3,7 @@
"id": "joy",
"version": "${version}",
"name": "Joy",
"description": "Joy is a Fabric mod built with the core goal of tastefully adding pride to Minecraft, while also porting Pridepack to its own set of decoration.",
"description": "${description}",
"authors": [
"Pridecraft Studios",
"Wolren",

View File

@ -5,6 +5,10 @@ version=1.0.0-alpha.1
group=gay.pridecraft
id=joy
github=https://git.pridecraft.gay/joy
description=Joy is a Fabric mod built with the core goal of tastefully adding pride to Minecraft, while also porting Pridepack to its own set of decoration.
deps.midnightlib=1.5.7-fabric
modrinthId=joy