diff --git a/README.md b/README.md
index ba3e978..e7289a4 100644
--- a/README.md
+++ b/README.md
@@ -66,6 +66,7 @@ jobs:
| changelog-file | A glob of the changelog file | ❌ | `CHANGELOG.md` |
| loaders | A list of supported mod loaders | `fabric` | `fabric`
`forge`
`rift` |
| game-versions | A list of supported Minecraft versions | Will be parsed from the `version` value (e.g., `0.40.0+1.18_experimental` results in `21w37a` and `21w38a` at the moment) | `21w37a`
`1.17` |
+| version-resolver | Determines the way automatic `game-versions` resolvement works | `releasesIfAny` | `exact` - exact game version *(`1.16` -> `1.16`)*
`latest` - the latest release of the given minor *(`1.16` -> `1.16.5`)*
`all` - all versions of the given minor starting with the specified build
`releases` - all releases of the given minor starting with the specified build *(`1.16.3` -> `[1.16.3, 1.16.4, 1.16.5]`)*
`releasesIfAny` - all releases of the given minor starting with the specified build, if any; otherwise, all versions |
| java | A list of supported Java versions | *empty string* | `Java 8`
`Java 1.8`
`8` |
### Minimalistic Example
diff --git a/action.yml b/action.yml
index db0bfb1..912b4c4 100644
--- a/action.yml
+++ b/action.yml
@@ -59,6 +59,9 @@ inputs:
game-versions:
description: A list of supported Minecraft versions
required: false
+ version-resolver:
+ description: Determines the way automatic game-versions resolvement works
+ required: false
java:
description: A list of supported Java versions
required: false
diff --git a/src/publishing/mod-publisher.ts b/src/publishing/mod-publisher.ts
index 35a6a57..079615c 100644
--- a/src/publishing/mod-publisher.ts
+++ b/src/publishing/mod-publisher.ts
@@ -1,8 +1,9 @@
import { context } from "@actions/github";
-import { getCompatibleBuilds, parseVersionNameFromFileVersion } from "../utils/minecraft-utils";
+import { parseVersionNameFromFileVersion } from "../utils/minecraft-utils";
import { File, getFiles, parseVersionFromFilename, parseVersionTypeFromFilename } from "../utils/file-utils";
import Publisher from "./publisher";
import PublisherTarget from "./publisher-target";
+import MinecraftVersionResolver from "../utils/minecraft-version-resolver";
interface ModPublisherOptions {
id: string;
@@ -12,6 +13,7 @@ interface ModPublisherOptions {
name?: string;
version?: string;
changelog?: string | { file?: string };
+ versionResolver?: string;
gameVersions?: string | string[];
java?: string | string[];
files?: string | { primary?: string, secondary?: string };
@@ -67,7 +69,8 @@ export default abstract class ModPublisher extends Publisher x.id));
+ const resolver = options.versionResolver && MinecraftVersionResolver.byName(options.versionResolver) || MinecraftVersionResolver.releasesIfAny;
+ gameVersions.push(...(await resolver.resolve(minecraftVersion)).map(x => x.id));
}
if (!gameVersions.length) {
throw new Error("At least one game version should be specified");
diff --git a/src/utils/game-version-resolver.ts b/src/utils/game-version-resolver.ts
new file mode 100644
index 0000000..8c03814
--- /dev/null
+++ b/src/utils/game-version-resolver.ts
@@ -0,0 +1,19 @@
+import Version from "./version";
+
+export default abstract class GameVersionResolver {
+ private readonly _filter: (version: string | Version, versions: TGameVersion[]) => TGameVersion[];
+
+ protected constructor(filter?: (version: string | Version, versions: TGameVersion[]) => TGameVersion[]) {
+ this._filter = filter || ((_, x) => x);
+ }
+
+ public async resolve(version: string | Version): Promise {
+ return this.filter(version, await this.getCompatibleVersions(version));
+ }
+
+ public filter(version: string | Version, versions: TGameVersion[]): TGameVersion[] {
+ return this._filter(version, versions);
+ }
+
+ public abstract getCompatibleVersions(version: string | Version): Promise;
+}
diff --git a/src/utils/minecraft-version-resolver.ts b/src/utils/minecraft-version-resolver.ts
new file mode 100644
index 0000000..d0d3b83
--- /dev/null
+++ b/src/utils/minecraft-version-resolver.ts
@@ -0,0 +1,24 @@
+import GameVersionResolver from "./game-version-resolver";
+import { getCompatibleBuilds, MinecraftVersion } from "./minecraft-utils";
+import Version from "./version";
+
+export default class MinecraftVersionResolver extends GameVersionResolver {
+ public static readonly exact = new MinecraftVersionResolver((n, v) => [v.find(x => x.version.equals(n))].filter(x => x));
+ public static readonly latest = new MinecraftVersionResolver((_, v) => v.find(x => x.isRelease) ? [v.find(x => x.isRelease)] : v.length ? [v[0]] : []);
+ public static readonly all = new MinecraftVersionResolver((_, v) => v);
+ public static readonly releases = new MinecraftVersionResolver((_, v) => v.filter(x => x.isRelease));
+ public static readonly releasesIfAny = new MinecraftVersionResolver((_, v) => v.find(x => x.isRelease) ? v.filter(x => x.isRelease) : v);
+
+ public static byName(name: string): MinecraftVersionResolver | null {
+ for (const [key, value] of Object.entries(MinecraftVersionResolver)) {
+ if (value instanceof MinecraftVersionResolver && key.localeCompare(name, undefined, { sensitivity: "accent" }) === 0) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+ public getCompatibleVersions(version: string | Version): Promise {
+ return getCompatibleBuilds(version);
+ }
+}
diff --git a/src/utils/version.ts b/src/utils/version.ts
index ff118a7..d37782e 100644
--- a/src/utils/version.ts
+++ b/src/utils/version.ts
@@ -16,4 +16,11 @@ export default class Version {
this.build = build || 0;
}
}
+
+ public equals(version: unknown): boolean {
+ if (version instanceof Version) {
+ return this.major === version.major && this.minor === version.minor && this.build === version.build;
+ }
+ return typeof version === "string" && this.equals(new Version(version));
+ }
}
diff --git a/test/minecraft-version-resolver.test.ts b/test/minecraft-version-resolver.test.ts
new file mode 100644
index 0000000..234024c
--- /dev/null
+++ b/test/minecraft-version-resolver.test.ts
@@ -0,0 +1,115 @@
+import { describe, test, expect } from "@jest/globals";
+import MinecraftVersionResolver from "../src/utils/minecraft-version-resolver";
+
+describe("MinecraftVersionResolver.byName", () => {
+ test("every predefined MinecraftVersionResolver can be resolved", () => {
+ for (const [key, value] of Object.entries(MinecraftVersionResolver).filter(([_, x]) => x instanceof MinecraftVersionResolver)) {
+ expect(MinecraftVersionResolver.byName(key)).toStrictEqual(value);
+ }
+ });
+
+ test("null is returned if MinecraftVersionResolver with the given name doesn't exist", () => {
+ expect(MinecraftVersionResolver.byName("non-existing-resolver")).toBeNull();
+ });
+
+ test("name of MinecraftVersionResolver is case insensitive", () => {
+ expect(MinecraftVersionResolver.byName("latest")).toStrictEqual(MinecraftVersionResolver.latest);
+ expect(MinecraftVersionResolver.byName("Latest")).toStrictEqual(MinecraftVersionResolver.latest);
+ expect(MinecraftVersionResolver.byName("LATEST")).toStrictEqual(MinecraftVersionResolver.latest);
+ expect(MinecraftVersionResolver.byName("LatesT")).toStrictEqual(MinecraftVersionResolver.latest);
+ });
+});
+
+describe("MinecraftVersionResolver.exact", () => {
+ test("the exact version is returned", async () => {
+ const _1_17 = (await MinecraftVersionResolver.exact.resolve("1.17")).map(x => x.id);
+ expect(_1_17).toHaveLength(1);
+ expect(_1_17).toContain("1.17");
+
+ const _1_17_1 = (await MinecraftVersionResolver.exact.resolve("1.17.1")).map(x => x.id);
+ expect(_1_17_1).toHaveLength(1);
+ expect(_1_17_1).toContain("1.17.1");
+ });
+
+ test("empty array is returned if no versions were found", async () => {
+ expect(await MinecraftVersionResolver.exact.resolve("42.0")).toHaveLength(0);
+ });
+});
+
+describe("MinecraftVersionResolver.latest", () => {
+ test("the latest version of the given minor is returned", async () => {
+ const versions = (await MinecraftVersionResolver.latest.resolve("1.17")).map(x => x.id);
+ expect(versions).toHaveLength(1);
+ expect(versions).toContain("1.17.1");
+ });
+
+ test("empty array is returned if no versions were found", async () => {
+ expect(await MinecraftVersionResolver.latest.resolve("42.0")).toHaveLength(0);
+ });
+});
+
+describe("MinecraftVersionResolver.all", () => {
+ test("all versions of the given minor are returned", async () => {
+ const versions = (await MinecraftVersionResolver.all.resolve("1.17")).map(x => x.id);
+ expect(versions).toHaveLength(31);
+ expect(versions).toContain("1.17");
+ expect(versions).toContain("1.17.1");
+ expect(versions).toContain("1.17.1-rc2");
+ expect(versions).toContain("1.17.1-rc1");
+ expect(versions).toContain("1.17.1-pre3");
+ expect(versions).toContain("1.17.1-pre2");
+ expect(versions).toContain("1.17.1-pre1");
+ expect(versions).toContain("21w03a");
+ });
+
+ test("all versions of the given minor starting with the given build are returned", async () => {
+ const versions = (await MinecraftVersionResolver.all.resolve("1.17.1")).map(x => x.id);
+ expect(versions).toHaveLength(6);
+ expect(versions).toContain("1.17.1");
+ expect(versions).toContain("1.17.1-rc2");
+ expect(versions).toContain("1.17.1-rc1");
+ expect(versions).toContain("1.17.1-pre3");
+ expect(versions).toContain("1.17.1-pre2");
+ expect(versions).toContain("1.17.1-pre1");
+ });
+
+ test("empty array is returned if no versions were found", async () => {
+ expect(await MinecraftVersionResolver.all.resolve("42.0")).toHaveLength(0);
+ });
+});
+
+describe("MinecraftVersionResolver.releases", () => {
+ test("all releases of the given minor are returned", async () => {
+ const versions = (await MinecraftVersionResolver.releases.resolve("1.17")).map(x => x.id);
+ expect(versions).toHaveLength(2);
+ expect(versions).toContain("1.17");
+ expect(versions).toContain("1.17.1");
+ });
+
+ test("all releases of the given minor starting with the given build are returned", async () => {
+ const versions = (await MinecraftVersionResolver.releases.resolve("1.16.1")).map(x => x.id);
+ expect(versions).toHaveLength(5);
+ expect(versions).toContain("1.16.1");
+ expect(versions).toContain("1.16.2");
+ expect(versions).toContain("1.16.3");
+ expect(versions).toContain("1.16.4");
+ expect(versions).toContain("1.16.5");
+ });
+
+ test("an empty array is returned if no versions were found", async () => {
+ expect(await MinecraftVersionResolver.releases.resolve("42.0")).toHaveLength(0);
+ });
+});
+
+describe("MinecraftVersionResolver.releasesIfAny", () => {
+ test("all releases of the given minor are returned", async () => {
+ const versions = (await MinecraftVersionResolver.releasesIfAny.resolve("1.17")).map(x => x.id);
+ expect(versions).toHaveLength(2);
+ expect(versions).toContain("1.17");
+ expect(versions).toContain("1.17.1");
+ });
+
+ test("empty array is returned if no versions were found", async () => {
+ expect(await MinecraftVersionResolver.releasesIfAny.resolve("42.0")).toHaveLength(0);
+ });
+});