Non-existing dependencies should cause a soft failure

This commit is contained in:
Kir_Antipov 2021-12-11 15:59:39 +03:00
parent af38f88370
commit 2194c72c22
2 changed files with 48 additions and 12 deletions

View file

@ -21,6 +21,13 @@ export default class CurseForgePublisher extends ModPublisher {
protected async publishMod(id: string, token: string, name: string, _version: string, channel: string, loaders: string[], gameVersions: string[], java: string[], changelog: string, files: File[], dependencies: Dependency[]): Promise<void> { protected async publishMod(id: string, token: string, name: string, _version: string, channel: string, loaders: string[], gameVersions: string[], java: string[], changelog: string, files: File[], dependencies: Dependency[]): Promise<void> {
let parentFileId = undefined; let parentFileId = undefined;
const versions = await convertToCurseForgeVersions(gameVersions, loaders, java, token); const versions = await convertToCurseForgeVersions(gameVersions, loaders, java, token);
const projects = dependencies
.filter((x, _, self) => x.kind !== DependencyKind.Suggests || !self.find(y => y.id === x.id && y.kind !== DependencyKind.Suggests))
.map(x => ({
slug: x.getProjectSlug(this.target),
type: forgeDependencyKinds.get(x.kind)
}))
.filter(x => x.slug && x.type);
for (const file of files) { for (const file of files) {
const data = { const data = {
@ -30,21 +37,34 @@ export default class CurseForgePublisher extends ModPublisher {
parentFileID: parentFileId, parentFileID: parentFileId,
releaseType: channel, releaseType: channel,
gameVersions: parentFileId ? undefined : versions, gameVersions: parentFileId ? undefined : versions,
relations: parentFileId ? undefined : { relations: (parentFileId || !projects.length) ? undefined : { projects }
projects: dependencies
.filter((x, _, self) => x.kind !== DependencyKind.Suggests || !self.find(y => y.id === x.id && y.kind !== DependencyKind.Suggests))
.map(x => ({
slug: x.getProjectSlug(this.target),
type: forgeDependencyKinds.get(x.kind)
}))
.filter(x => x.slug && x.type)
}
}; };
const fileId = await uploadFile(id, data, file, token); const fileId = await this.upload(id, data, file, token);
if (!parentFileId) { if (!parentFileId) {
parentFileId = fileId; parentFileId = fileId;
} }
} }
} }
private async upload(id: string, data: Record<string, any>, file: File, token: string): Promise<number | never> {
while (true) {
try {
return await uploadFile(id, data, file, token);
} catch (error) {
if (error?.info?.errorCode === 1018 && typeof error.info.errorMessage === "string") {
const match = error.info.errorMessage.match(/Invalid slug in project relations: '([^']+)'/);
const projects = <{ slug: string }[]>data.relations?.projects;
if (match && projects?.length) {
const invalidSlugIndex = projects.findIndex(x => x.slug === match[1]);
if (invalidSlugIndex !== -1) {
projects.splice(invalidSlugIndex, 1);
continue;
}
}
}
throw error;
}
}
}
} }

View file

@ -19,6 +19,20 @@ interface CurseForgeVersions {
java: CurseForgeVersion[]; java: CurseForgeVersion[];
} }
interface CurseForgeUploadErrorInfo {
errorCode: number;
errorMessage: string;
}
class CurseForgeUploadError extends Error {
public readonly info?: CurseForgeUploadErrorInfo;
constructor(message: string, info?: CurseForgeUploadErrorInfo) {
super(message);
this.info = info;
}
}
let cachedCurseForgeVersions: CurseForgeVersions = null; let cachedCurseForgeVersions: CurseForgeVersions = null;
async function getCurseForgeVersions(token: string): Promise<CurseForgeVersions> { async function getCurseForgeVersions(token: string): Promise<CurseForgeVersions> {
@ -98,10 +112,12 @@ export async function uploadFile(id: string, data: Record<string, any>, file: Fi
if (!response.ok) { if (!response.ok) {
let errorText = response.statusText; let errorText = response.statusText;
let info: CurseForgeUploadErrorInfo;
try { try {
errorText += `, ${await response.text()}`; info = <CurseForgeUploadErrorInfo>await response.json();
errorText += `, ${JSON.stringify(info)}`;
} catch { } } catch { }
throw new Error(`Failed to upload file: ${response.status} (${errorText})`); throw new CurseForgeUploadError(`Failed to upload file: ${response.status} (${errorText})`, info);
} }
return (<{ id: number }>await response.json()).id; return (<{ id: number }>await response.json()).id;