ModPublisher can use mod metadata now

This commit is contained in:
Kir_Antipov 2021-12-08 16:42:53 +03:00
parent 7cc4b5d26f
commit 5e7fd885b0

View file

@ -1,10 +1,15 @@
import { context } from "@actions/github"; import { context } from "@actions/github";
import { parseVersionName, parseVersionNameFromFileVersion } from "../utils/minecraft-utils";
import { File } from "../utils/file"; import { File } from "../utils/file";
import { getFiles } from "../utils/file-utils"; import { getFiles } from "../utils/file-utils";
import Publisher from "./publisher"; import Publisher from "./publisher";
import PublisherTarget from "./publisher-target"; import PublisherTarget from "./publisher-target";
import MinecraftVersionResolver from "../utils/minecraft-version-resolver"; import MinecraftVersionResolver from "../utils/minecraft-version-resolver";
import ModMetadataReader from "../metadata/mod-metadata-reader";
import Dependency from "../metadata/dependency";
import { parseVersionFromName, parseVersionTypeFromName } from "../utils/version-utils"; import { parseVersionFromName, parseVersionTypeFromName } from "../utils/version-utils";
import DependencyKind from "../metadata/dependency-kind";
import path from "path";
interface ModPublisherOptions { interface ModPublisherOptions {
id: string; id: string;
@ -17,11 +22,10 @@ interface ModPublisherOptions {
versionResolver?: string; versionResolver?: string;
gameVersions?: string | string[]; gameVersions?: string | string[];
java?: string | string[]; java?: string | string[];
dependencies?: string | string[];
files?: string | { primary?: string, secondary?: string }; files?: string | { primary?: string, secondary?: string };
} }
const defaultLoaders = ["fabric"];
function processMultilineInput(input: string | string[], splitter?: RegExp): string[] { function processMultilineInput(input: string | string[], splitter?: RegExp): string[] {
if (!input) { if (!input) {
return []; return [];
@ -29,12 +33,20 @@ function processMultilineInput(input: string | string[], splitter?: RegExp): str
return (typeof input === "string" ? input.split(splitter || /(\r?\n)+/) : input).map(x => x.trim()).filter(x => x); return (typeof input === "string" ? input.split(splitter || /(\r?\n)+/) : input).map(x => x.trim()).filter(x => x);
} }
async function readChangelog(changelog: string | { file?: string }): Promise<string | never> { function processDependenciesInput(input: string | string[], inputSplitter?: RegExp, entrySplitter?: RegExp): Dependency[] {
if (typeof changelog === "string") { return processMultilineInput(input, inputSplitter).map(x => {
return changelog; const parts = x.split(entrySplitter || /\|/);
} const id = parts[0].trim();
return Dependency.create({
id,
kind: parts[1] && DependencyKind.parse(parts[1].trim()) || DependencyKind.Depends,
version: parts[2]?.trim() || "*"
});
});
}
const file = (await getFiles(changelog.file || ""))[0]; async function readChangelog(changelogPath: string): Promise<string | never> {
const file = (await getFiles(changelogPath))[0];
if (!file) { if (!file) {
throw new Error("Changelog file was not found"); throw new Error("Changelog file was not found");
} }
@ -46,9 +58,8 @@ export default abstract class ModPublisher extends Publisher<ModPublisherOptions
this.validateOptions(options); this.validateOptions(options);
const releaseInfo = <any>context.payload.release; const releaseInfo = <any>context.payload.release;
const id = options.id; if (!Array.isArray(files) || !files.length) {
if (!id) { throw new Error("No upload files were specified");
throw new Error(`Project id is required to publish your assets to ${PublisherTarget.toString(this.target)}`);
} }
const token = options.token; const token = options.token;
@ -56,19 +67,39 @@ export default abstract class ModPublisher extends Publisher<ModPublisherOptions
throw new Error(`Token is required to publish your assets to ${PublisherTarget.toString(this.target)}`); throw new Error(`Token is required to publish your assets to ${PublisherTarget.toString(this.target)}`);
} }
const version = (typeof options.version === "string" && options.version) || <string>releaseInfo?.tag_name || parseVersionFromFilename(files[0].name); const metadata = await ModMetadataReader.readMetadata(files[0].path);
const versionType = options.versionType?.toLowerCase() || parseVersionTypeFromFilename(files[0].name);
const id = options.id || metadata?.getProjectId(this.target);
if (!id) {
throw new Error(`Project id is required to publish your assets to ${PublisherTarget.toString(this.target)}`);
}
const filename = path.parse(files[0].path).name;
const version = (typeof options.version === "string" && options.version) || <string>releaseInfo?.tag_name || metadata?.version || parseVersionFromName(filename);
const versionType = options.versionType?.toLowerCase() || parseVersionTypeFromName(metadata?.version || filename);
const name = typeof options.name === "string" ? options.name : (<string>releaseInfo?.name || version); const name = typeof options.name === "string" ? options.name : (<string>releaseInfo?.name || version);
const changelog = ((typeof options.changelog === "string" || options.changelog?.file) ? (await readChangelog(options.changelog)) : <string>releaseInfo?.body) || ""; const changelog = typeof options.changelog === "string"
? options.changelog
: typeof options.changelog?.file === "string"
? await readChangelog(options.changelog.file)
: <string>releaseInfo?.body || "";
const loaders = processMultilineInput(options.loaders, /\s+/); const loaders = processMultilineInput(options.loaders, /\s+/);
if (!loaders.length) { if (!loaders.length) {
loaders.push(...defaultLoaders); if (metadata) {
loaders.push(...metadata.loaders);
}
if (!loaders.length) {
throw new Error("At least one mod loader should be specified");
}
} }
const gameVersions = processMultilineInput(options.gameVersions); const gameVersions = processMultilineInput(options.gameVersions);
if (!gameVersions.length) { if (!gameVersions.length) {
const minecraftVersion = parseVersionNameFromFileVersion(version); const minecraftVersion =
metadata?.dependencies.filter(x => x.id === "minecraft").map(x => parseVersionName(x.version))[0] ||
parseVersionNameFromFileVersion(version);
if (minecraftVersion) { if (minecraftVersion) {
const resolver = options.versionResolver && MinecraftVersionResolver.byName(options.versionResolver) || MinecraftVersionResolver.releasesIfAny; const resolver = options.versionResolver && MinecraftVersionResolver.byName(options.versionResolver) || MinecraftVersionResolver.releasesIfAny;
gameVersions.push(...(await resolver.resolve(minecraftVersion)).map(x => x.id)); gameVersions.push(...(await resolver.resolve(minecraftVersion)).map(x => x.id));
@ -79,9 +110,13 @@ export default abstract class ModPublisher extends Publisher<ModPublisherOptions
} }
const java = processMultilineInput(options.java); const java = processMultilineInput(options.java);
const dependencies = typeof options.dependencies === "string"
? processDependenciesInput(options.dependencies)
: metadata?.dependencies || [];
const uniqueDependencies = dependencies.filter((x, i, self) => !x.ignore && self.findIndex(y => y.id === x.id && y.kind === x.kind) === i);
await this.publishMod(id, token, name, version, versionType, loaders, gameVersions, java, changelog, files); await this.publishMod(id, token, name, version, versionType, loaders, gameVersions, java, changelog, files, uniqueDependencies);
} }
protected abstract publishMod(id: string, token: string, name: string, version: string, versionType: string, loaders: string[], gameVersions: string[], java: string[], changelog: string, files: File[]): Promise<void>; protected abstract publishMod(id: string, token: string, name: string, version: string, versionType: string, loaders: string[], gameVersions: string[], java: string[], changelog: string, files: File[], dependencies: Dependency[]): Promise<void>;
} }