semantic-release-minecraft 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/curseforge.d.ts +2 -2
- package/dist/curseforge.d.ts.map +1 -1
- package/dist/curseforge.js +47 -115
- package/dist/curseforge.js.map +1 -1
- package/dist/definitions/curseforge.d.ts +6 -6
- package/dist/definitions/{plugin_config.d.ts → plugin-config.d.ts} +4 -3
- package/dist/definitions/plugin-config.d.ts.map +1 -0
- package/dist/definitions/plugin-config.js +2 -0
- package/dist/definitions/plugin-config.js.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -23
- package/dist/index.js.map +1 -1
- package/dist/modrinth.d.ts +3 -3
- package/dist/modrinth.d.ts.map +1 -1
- package/dist/modrinth.js +58 -223
- package/dist/modrinth.js.map +1 -1
- package/dist/prepare.d.ts +4 -8
- package/dist/prepare.d.ts.map +1 -1
- package/dist/prepare.js +31 -32
- package/dist/prepare.js.map +1 -1
- package/dist/utils/glob-utils.d.ts +6 -0
- package/dist/utils/glob-utils.d.ts.map +1 -0
- package/dist/utils/glob-utils.js +27 -0
- package/dist/utils/glob-utils.js.map +1 -0
- package/dist/utils/platform/curseforge-utils.d.ts +4 -0
- package/dist/utils/platform/curseforge-utils.d.ts.map +1 -0
- package/dist/utils/platform/curseforge-utils.js +7 -0
- package/dist/utils/platform/curseforge-utils.js.map +1 -0
- package/dist/utils/platform/utils.d.ts +10 -0
- package/dist/utils/platform/utils.d.ts.map +1 -0
- package/dist/utils/platform/utils.js +56 -0
- package/dist/utils/platform/utils.js.map +1 -0
- package/dist/utils/template-utils.d.ts +26 -0
- package/dist/utils/template-utils.d.ts.map +1 -0
- package/dist/utils/template-utils.js +40 -0
- package/dist/utils/template-utils.js.map +1 -0
- package/dist/utils/utils.d.ts +4 -26
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +5 -79
- package/dist/utils/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/curseforge.ts +98 -160
- package/src/definitions/curseforge.ts +6 -6
- package/src/definitions/plugin-config.ts +68 -0
- package/src/index.ts +28 -34
- package/src/modrinth.ts +78 -271
- package/src/prepare.ts +43 -52
- package/src/utils/glob-utils.ts +38 -0
- package/src/utils/platform/curseforge-utils.ts +17 -0
- package/src/utils/platform/utils.ts +84 -0
- package/src/utils/template-utils.ts +54 -0
- package/src/utils/utils.ts +5 -115
- package/dist/definitions/plugin_config.d.ts.map +0 -1
- package/dist/definitions/plugin_config.js +0 -2
- package/dist/definitions/plugin_config.js.map +0 -1
- package/src/definitions/plugin_config.ts +0 -68
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export type PluginConfig = {
|
|
2
|
+
release_type?: 'alpha' | 'beta' | 'release';
|
|
3
|
+
game_versions?: string | string[];
|
|
4
|
+
mod_loaders?: string | string[];
|
|
5
|
+
display_name?: string;
|
|
6
|
+
|
|
7
|
+
// Global release strategy configuration for multiple publish operations
|
|
8
|
+
strategies?: Record<string, string>[];
|
|
9
|
+
|
|
10
|
+
glob?: string | string[];
|
|
11
|
+
primary_file_glob: string | string[];
|
|
12
|
+
|
|
13
|
+
curseforge?: {
|
|
14
|
+
project_id: string;
|
|
15
|
+
game_versions?: string | string[];
|
|
16
|
+
java_versions?: string | string[];
|
|
17
|
+
environments?: string | string[];
|
|
18
|
+
game_versions_for_plugins?: string | string[];
|
|
19
|
+
game_versions_for_addon?: string | string[];
|
|
20
|
+
mod_loaders?: string | string[];
|
|
21
|
+
changelog?: string;
|
|
22
|
+
changelog_type?: 'text' | 'html' | 'markdown';
|
|
23
|
+
display_name?: string;
|
|
24
|
+
is_marked_for_manual_release?: boolean;
|
|
25
|
+
relations?: {
|
|
26
|
+
projects?: Array<{
|
|
27
|
+
slug: string;
|
|
28
|
+
project_id?: string;
|
|
29
|
+
type:
|
|
30
|
+
| 'embedded_library'
|
|
31
|
+
| 'incompatible'
|
|
32
|
+
| 'optional_dependency'
|
|
33
|
+
| 'required_dependency'
|
|
34
|
+
| 'tool';
|
|
35
|
+
}>;
|
|
36
|
+
};
|
|
37
|
+
glob?: string | string[];
|
|
38
|
+
};
|
|
39
|
+
modrinth?: {
|
|
40
|
+
project_id: string;
|
|
41
|
+
version_number?: string;
|
|
42
|
+
display_name?: string;
|
|
43
|
+
game_versions?: string[];
|
|
44
|
+
mod_loaders?: string[];
|
|
45
|
+
changelog?: string;
|
|
46
|
+
dependencies?: Array<{
|
|
47
|
+
version_id?: string;
|
|
48
|
+
project_id?: string;
|
|
49
|
+
file_name?: string;
|
|
50
|
+
dependency_type:
|
|
51
|
+
| 'required'
|
|
52
|
+
| 'optional'
|
|
53
|
+
| 'incompatible'
|
|
54
|
+
| 'embedded';
|
|
55
|
+
}>;
|
|
56
|
+
featured?: boolean;
|
|
57
|
+
status?:
|
|
58
|
+
| 'listed'
|
|
59
|
+
| 'archived'
|
|
60
|
+
| 'draft'
|
|
61
|
+
| 'unlisted'
|
|
62
|
+
| 'scheduled'
|
|
63
|
+
| 'unknown';
|
|
64
|
+
requested_status?: 'listed' | 'archived' | 'draft' | 'unlisted';
|
|
65
|
+
glob?: string | string[];
|
|
66
|
+
primary_file_glob?: string | string[];
|
|
67
|
+
};
|
|
68
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -4,69 +4,63 @@ import {
|
|
|
4
4
|
VerifyConditionsContext,
|
|
5
5
|
} from 'semantic-release';
|
|
6
6
|
import { publishToCurseforge } from './curseforge.js';
|
|
7
|
-
import {
|
|
7
|
+
import { PluginConfig } from './definitions/plugin-config.js';
|
|
8
8
|
import { publishToModrinth } from './modrinth.js';
|
|
9
9
|
import { getCurseForgeGameVersionIds } from './prepare.js';
|
|
10
10
|
|
|
11
|
-
//
|
|
11
|
+
// Game version IDs transformed from user's input, used during publishing to CurseForge
|
|
12
12
|
let curseforgeGameVersionsIds: number[] | undefined;
|
|
13
13
|
|
|
14
14
|
export async function verifyConditions(
|
|
15
|
-
pluginConfig:
|
|
15
|
+
pluginConfig: PluginConfig,
|
|
16
16
|
context: VerifyConditionsContext
|
|
17
17
|
) {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const { env } = context;
|
|
19
|
+
|
|
20
|
+
if (env.CURSEFORGE_TOKEN && !pluginConfig.curseforge?.project_id) {
|
|
20
21
|
throw new Error('CurseForge project ID is required');
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
if (
|
|
24
|
+
if (env.MODRINTH_TOKEN && !pluginConfig.modrinth?.project_id) {
|
|
24
25
|
throw new Error('Modrinth project ID is required');
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export async function prepare(
|
|
29
|
-
pluginConfig:
|
|
30
|
+
pluginConfig: PluginConfig,
|
|
30
31
|
context: PrepareContext
|
|
31
32
|
) {
|
|
32
33
|
const { env, logger } = context;
|
|
33
34
|
|
|
34
35
|
if (env.CURSEFORGE_TOKEN) {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
logger.log('Fetching CurseForge game versions and types...');
|
|
36
|
+
const apiToken = env.CURSEFORGE_TOKEN;
|
|
37
|
+
logger.log('Fetching CurseForge game versions and types...');
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
context.nextRelease
|
|
45
|
-
);
|
|
39
|
+
curseforgeGameVersionsIds = await getCurseForgeGameVersionIds(
|
|
40
|
+
apiToken,
|
|
41
|
+
pluginConfig,
|
|
42
|
+
context
|
|
43
|
+
);
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
} catch (error) {
|
|
51
|
-
logger.warn(
|
|
52
|
-
`Failed to fetch CurseForge game versions: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
53
|
-
);
|
|
54
|
-
}
|
|
45
|
+
logger.log(
|
|
46
|
+
`Successfully transform into ${Object.keys(curseforgeGameVersionsIds).length} CurseForge game versions`
|
|
47
|
+
);
|
|
55
48
|
}
|
|
56
49
|
}
|
|
57
50
|
|
|
58
51
|
export async function publish(
|
|
59
|
-
pluginConfig:
|
|
52
|
+
pluginConfig: PluginConfig,
|
|
60
53
|
context: PublishContext
|
|
61
54
|
): Promise<{ url: string }[]> {
|
|
62
55
|
const { env, logger } = context;
|
|
63
56
|
const results: { url: string }[] = [];
|
|
64
57
|
|
|
65
|
-
|
|
58
|
+
for (const strategy of pluginConfig.strategies || [{}]) {
|
|
66
59
|
if (env.CURSEFORGE_TOKEN) {
|
|
67
60
|
const curseforgeId = await publishToCurseforge(
|
|
68
61
|
pluginConfig,
|
|
69
62
|
context,
|
|
63
|
+
strategy,
|
|
70
64
|
curseforgeGameVersionsIds
|
|
71
65
|
);
|
|
72
66
|
results.push({
|
|
@@ -78,9 +72,12 @@ export async function publish(
|
|
|
78
72
|
);
|
|
79
73
|
}
|
|
80
74
|
|
|
81
|
-
// 发布到 Modrinth(如果配置了 Modrinth 且存在环境变量)
|
|
82
75
|
if (env.MODRINTH_TOKEN) {
|
|
83
|
-
const modrinthId = await publishToModrinth(
|
|
76
|
+
const modrinthId = await publishToModrinth(
|
|
77
|
+
pluginConfig,
|
|
78
|
+
context,
|
|
79
|
+
strategy
|
|
80
|
+
);
|
|
84
81
|
results.push({
|
|
85
82
|
url: `https://modrinth.com/mod/${pluginConfig.modrinth!.project_id}/version/${modrinthId}`,
|
|
86
83
|
});
|
|
@@ -89,10 +86,7 @@ export async function publish(
|
|
|
89
86
|
'Modrinth publishing is skipped: MODRINTH_TOKEN environment variable not found.'
|
|
90
87
|
);
|
|
91
88
|
}
|
|
92
|
-
|
|
93
|
-
return results;
|
|
94
|
-
} catch (error) {
|
|
95
|
-
logger.error('Failed to publish:', error);
|
|
96
|
-
throw error;
|
|
97
89
|
}
|
|
90
|
+
|
|
91
|
+
return results;
|
|
98
92
|
}
|
package/src/modrinth.ts
CHANGED
|
@@ -1,331 +1,138 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import FormData from 'form-data';
|
|
3
3
|
import { readFile } from 'fs/promises';
|
|
4
|
-
import {
|
|
5
|
-
import _ from 'lodash';
|
|
6
|
-
import { resolve } from 'path';
|
|
4
|
+
import { basename } from 'path';
|
|
7
5
|
import { PublishContext } from 'semantic-release';
|
|
8
|
-
import {
|
|
6
|
+
import { PluginConfig } from './definitions/plugin-config';
|
|
7
|
+
import { findFilesAndPrimaryFile } from './utils/platform/utils';
|
|
9
8
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
resolveTemplate,
|
|
14
|
-
toArray,
|
|
15
|
-
} from './utils/utils.js';
|
|
9
|
+
resolveAndRenderTemplate,
|
|
10
|
+
resolveAndRenderTemplates,
|
|
11
|
+
} from './utils/template-utils';
|
|
16
12
|
|
|
17
13
|
/**
|
|
18
|
-
*
|
|
14
|
+
* Publishes files to Modrinth.
|
|
19
15
|
*/
|
|
20
16
|
export async function publishToModrinth(
|
|
21
|
-
pluginConfig:
|
|
22
|
-
context: PublishContext
|
|
17
|
+
pluginConfig: PluginConfig,
|
|
18
|
+
context: PublishContext,
|
|
19
|
+
strategy: Record<string, string>
|
|
23
20
|
): Promise<string> {
|
|
24
|
-
const { env, logger } = context;
|
|
21
|
+
const { env, logger, nextRelease } = context;
|
|
25
22
|
const { modrinth } = pluginConfig;
|
|
26
23
|
const token = env.MODRINTH_TOKEN!;
|
|
27
24
|
const projectId = modrinth?.project_id!;
|
|
28
|
-
const nextRelease = context.nextRelease;
|
|
29
|
-
const nextReleaseVersion = nextRelease.version;
|
|
30
25
|
|
|
31
|
-
|
|
32
|
-
const { files, primaryFile } = await findModrinthFiles(
|
|
26
|
+
const { files, primaryFile } = await findFilesAndPrimaryFile(
|
|
33
27
|
pluginConfig,
|
|
34
|
-
context
|
|
28
|
+
context,
|
|
29
|
+
strategy
|
|
35
30
|
);
|
|
36
31
|
logger.log(
|
|
37
32
|
`Publishing ${files.length} file(s) to Modrinth project ${projectId}...`
|
|
38
33
|
);
|
|
39
34
|
|
|
40
|
-
//
|
|
35
|
+
// use multipart/form-data to upload files and version data
|
|
41
36
|
const form = new FormData();
|
|
42
37
|
const filePartNames: string[] = [];
|
|
43
38
|
let primaryFilePartName: string | undefined = undefined;
|
|
44
39
|
|
|
45
|
-
// 上传所有文件
|
|
46
40
|
for (let i = 0; i < files.length; i++) {
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const fileName =
|
|
41
|
+
const filePath = files[i];
|
|
42
|
+
const file = await readFile(filePath);
|
|
43
|
+
const fileName = basename(filePath);
|
|
44
|
+
|
|
50
45
|
const filePartName = `file-${i}`;
|
|
51
46
|
|
|
52
|
-
form.append(filePartName,
|
|
47
|
+
form.append(filePartName, file, { filename: fileName });
|
|
53
48
|
filePartNames.push(filePartName);
|
|
54
49
|
|
|
55
|
-
|
|
56
|
-
if (jarPath === primaryFile) {
|
|
50
|
+
if (filePath === primaryFile) {
|
|
57
51
|
primaryFilePartName = filePartName;
|
|
58
52
|
}
|
|
59
53
|
}
|
|
60
54
|
|
|
61
|
-
// 使用根据 primaryFileGlob 确定的主要文件
|
|
62
|
-
const finalPrimaryFile: string | undefined = primaryFilePartName;
|
|
63
|
-
|
|
64
|
-
// 准备版本信息,只包含必需字段和存在的可选字段
|
|
65
|
-
// displayName 按照优先级:平台特定配置 > 全局配置 > 平台特定环境变量 > 全局环境变量
|
|
66
|
-
let displayName: string | undefined;
|
|
67
|
-
if (modrinth?.display_name) {
|
|
68
|
-
displayName = _.template(modrinth.display_name)({
|
|
69
|
-
nextRelease,
|
|
70
|
-
}) as string;
|
|
71
|
-
} else if (pluginConfig.display_name) {
|
|
72
|
-
displayName = _.template(pluginConfig.display_name)({
|
|
73
|
-
nextRelease,
|
|
74
|
-
}) as string;
|
|
75
|
-
} else if (env.MODRINTH_DISPLAY_NAME) {
|
|
76
|
-
displayName = env.MODRINTH_DISPLAY_NAME;
|
|
77
|
-
} else if (env.DISPLAY_NAME) {
|
|
78
|
-
displayName = env.DISPLAY_NAME;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// version_number 按照优先级:平台特定配置 > 平台特定环境变量 > 全局环境变量
|
|
82
|
-
const versionNumber = resolveTemplate(
|
|
83
|
-
[modrinth?.version_number, env.MODRINTH_VERSION_NUMBER],
|
|
84
|
-
{ nextRelease }
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
// 准备版本信息,只包含必需字段和存在的可选字段
|
|
88
55
|
const versionData: any = {
|
|
89
56
|
project_id: projectId,
|
|
90
|
-
file_parts: filePartNames,
|
|
57
|
+
file_parts: filePartNames,
|
|
58
|
+
changelog: modrinth?.changelog || nextRelease.notes || '',
|
|
59
|
+
loaders: modrinth?.mod_loaders || [],
|
|
60
|
+
version_type: pluginConfig.release_type || 'release',
|
|
61
|
+
dependencies: modrinth?.dependencies || [],
|
|
62
|
+
featured: modrinth?.featured || false,
|
|
63
|
+
status: modrinth?.status || 'listed',
|
|
64
|
+
requested_status: modrinth?.requested_status || 'listed',
|
|
65
|
+
primary_file: primaryFilePartName,
|
|
91
66
|
};
|
|
92
67
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
} else {
|
|
97
|
-
// 如果没有找到任何配置,使用默认值
|
|
98
|
-
versionData.name = context.nextRelease.name;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// 只有找到值时才添加 version_number 字段
|
|
102
|
-
if (versionNumber) {
|
|
103
|
-
versionData.version_number = versionNumber;
|
|
104
|
-
} else {
|
|
105
|
-
// 如果没有找到任何配置,使用默认值
|
|
106
|
-
versionData.version_number = nextReleaseVersion;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// 只添加存在的可选字段
|
|
110
|
-
if (modrinth?.changelog || context.nextRelease?.notes) {
|
|
111
|
-
versionData.changelog =
|
|
112
|
-
modrinth?.changelog || context.nextRelease?.notes || '';
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (modrinth?.game_versions && modrinth.game_versions.length > 0) {
|
|
116
|
-
versionData.game_versions = renderTemplates(modrinth.game_versions, {
|
|
117
|
-
nextRelease,
|
|
118
|
-
}) as string[];
|
|
119
|
-
} else if (
|
|
120
|
-
pluginConfig.game_versions &&
|
|
121
|
-
pluginConfig.game_versions.length > 0
|
|
122
|
-
) {
|
|
123
|
-
versionData.game_versions = renderTemplates(
|
|
124
|
-
toArray(pluginConfig.game_versions),
|
|
125
|
-
{
|
|
126
|
-
nextRelease,
|
|
127
|
-
}
|
|
128
|
-
) as string[];
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// modLoaders 按照优先级:平台特定配置 > 全局配置 > 平台特定环境变量 > 全局环境变量
|
|
132
|
-
let modLoaders: string[] | undefined;
|
|
133
|
-
if (modrinth?.mod_loaders && modrinth.mod_loaders.length > 0) {
|
|
134
|
-
modLoaders = renderTemplates(modrinth.mod_loaders, {
|
|
135
|
-
nextRelease,
|
|
136
|
-
}) as string[];
|
|
137
|
-
} else if (
|
|
138
|
-
pluginConfig.mod_loaders &&
|
|
139
|
-
pluginConfig.mod_loaders.length > 0
|
|
140
|
-
) {
|
|
141
|
-
modLoaders = renderTemplates(toArray(pluginConfig.mod_loaders), {
|
|
68
|
+
const displayName = resolveAndRenderTemplate(
|
|
69
|
+
[modrinth?.display_name, pluginConfig.display_name],
|
|
70
|
+
{
|
|
142
71
|
nextRelease,
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
} else if (env.MOD_LOADERS) {
|
|
147
|
-
modLoaders = env.MOD_LOADERS.split(',').map((s) => s.trim());
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (modLoaders) {
|
|
151
|
-
versionData.loaders = modLoaders;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (pluginConfig.release_type) {
|
|
155
|
-
versionData.version_type = pluginConfig.release_type;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (modrinth?.dependencies && modrinth.dependencies.length > 0) {
|
|
159
|
-
versionData.dependencies = modrinth.dependencies;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (modrinth?.featured !== undefined) {
|
|
163
|
-
versionData.featured = modrinth.featured;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (modrinth?.status) {
|
|
167
|
-
versionData.status = modrinth.status;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (modrinth?.requested_status) {
|
|
171
|
-
versionData.requested_status = modrinth.requested_status;
|
|
172
|
-
}
|
|
72
|
+
...strategy,
|
|
73
|
+
}
|
|
74
|
+
);
|
|
173
75
|
|
|
174
|
-
|
|
175
|
-
if (finalPrimaryFile) {
|
|
176
|
-
versionData.primary_file = finalPrimaryFile;
|
|
177
|
-
}
|
|
76
|
+
versionData.name = displayName || nextRelease.name;
|
|
178
77
|
|
|
179
|
-
|
|
180
|
-
|
|
78
|
+
const versionNumber = resolveAndRenderTemplate([modrinth?.version_number], {
|
|
79
|
+
nextRelease,
|
|
80
|
+
...strategy,
|
|
81
|
+
});
|
|
181
82
|
|
|
182
|
-
|
|
183
|
-
try {
|
|
184
|
-
const versionResponse = await axios.post(
|
|
185
|
-
'https://api.modrinth.com/v2/version',
|
|
186
|
-
form,
|
|
187
|
-
{
|
|
188
|
-
headers: {
|
|
189
|
-
...form.getHeaders(),
|
|
190
|
-
Authorization: token,
|
|
191
|
-
},
|
|
192
|
-
validateStatus: (status) => status < 500, // 仅拒绝5xx错误
|
|
193
|
-
}
|
|
194
|
-
);
|
|
83
|
+
versionData.version_number = versionNumber || nextRelease.version;
|
|
195
84
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
);
|
|
202
|
-
return versionResponse.data.id;
|
|
203
|
-
} else if (
|
|
204
|
-
versionResponse.status === 400 ||
|
|
205
|
-
versionResponse.status === 401
|
|
206
|
-
) {
|
|
207
|
-
// 处理客户端错误
|
|
208
|
-
const data = versionResponse.data;
|
|
209
|
-
if (data && data.error && data.description) {
|
|
210
|
-
logger.error(
|
|
211
|
-
`Modrinth API Error (${versionResponse.status}): ${data.error} - ${data.description}`
|
|
212
|
-
);
|
|
213
|
-
throw new Error(
|
|
214
|
-
`Modrinth发布失败: ${data.error} - ${data.description}`
|
|
215
|
-
);
|
|
216
|
-
} else {
|
|
217
|
-
logger.error(
|
|
218
|
-
`Modrinth API Error (${versionResponse.status}): ${JSON.stringify(data)}`
|
|
219
|
-
);
|
|
220
|
-
throw new Error(
|
|
221
|
-
`Modrinth发布失败 (状态码: ${versionResponse.status}): ${JSON.stringify(data)}`
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
} else {
|
|
225
|
-
// 其他错误状态码
|
|
226
|
-
const data = versionResponse.data;
|
|
227
|
-
logger.error(
|
|
228
|
-
`Modrinth API Error (${versionResponse.status}): ${JSON.stringify(data)}`
|
|
229
|
-
);
|
|
230
|
-
throw new Error(
|
|
231
|
-
`Modrinth发布失败 (状态码: ${versionResponse.status}): ${JSON.stringify(data)}`
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
} catch (error: any) {
|
|
235
|
-
if (error.response) {
|
|
236
|
-
// 已经在上面处理过
|
|
237
|
-
throw error;
|
|
238
|
-
} else if (error.request) {
|
|
239
|
-
// 请求已发送但未收到响应
|
|
240
|
-
logger.error('Modrinth API 请求失败,未收到响应');
|
|
241
|
-
throw new Error('Modrinth发布失败: 未收到服务器响应');
|
|
242
|
-
} else {
|
|
243
|
-
// 请求配置出错
|
|
244
|
-
logger.error('Modrinth API 请求配置错误:', error.message);
|
|
245
|
-
throw new Error(`Modrinth发布失败: ${error.message}`);
|
|
85
|
+
const gameVersions = resolveAndRenderTemplates(
|
|
86
|
+
[modrinth?.game_versions, pluginConfig.game_versions],
|
|
87
|
+
{
|
|
88
|
+
nextRelease,
|
|
89
|
+
...strategy,
|
|
246
90
|
}
|
|
247
|
-
|
|
248
|
-
}
|
|
91
|
+
);
|
|
249
92
|
|
|
250
|
-
|
|
251
|
-
* 为 Modrinth 查找文件并确定主要文件
|
|
252
|
-
*/
|
|
253
|
-
async function findModrinthFiles(
|
|
254
|
-
pluginConfig: Plugin_config,
|
|
255
|
-
context: PublishContext
|
|
256
|
-
): Promise<{ files: string[]; primaryFile: string | undefined }> {
|
|
257
|
-
const { env, logger } = context;
|
|
93
|
+
versionData.game_versions = gameVersions || [];
|
|
258
94
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
[
|
|
262
|
-
pluginConfig.modrinth?.glob,
|
|
263
|
-
pluginConfig.glob,
|
|
264
|
-
env.MODRINTH_GLOB,
|
|
265
|
-
env.GLOB,
|
|
266
|
-
],
|
|
95
|
+
const modLoaders = resolveAndRenderTemplates(
|
|
96
|
+
[modrinth?.mod_loaders, pluginConfig.mod_loaders],
|
|
267
97
|
{
|
|
268
|
-
nextRelease
|
|
98
|
+
nextRelease,
|
|
99
|
+
...strategy,
|
|
269
100
|
}
|
|
270
101
|
);
|
|
271
102
|
|
|
272
|
-
|
|
273
|
-
const jarFiles = await findFiles(modrinthGlob, context);
|
|
274
|
-
logger.log(
|
|
275
|
-
`Found ${jarFiles.length} JAR file(s) for Modrinth: ${jarFiles.join(', ')}`
|
|
276
|
-
);
|
|
103
|
+
versionData.mod_loaders = modLoaders || [];
|
|
277
104
|
|
|
278
|
-
|
|
279
|
-
let primaryFile: string | undefined = undefined;
|
|
105
|
+
form.append('data', versionData);
|
|
280
106
|
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
env.MODRINTH_PRIMARY_FILE_GLOB,
|
|
285
|
-
],
|
|
107
|
+
const versionResponse = await axios.post(
|
|
108
|
+
'https://api.modrinth.com/v2/version',
|
|
109
|
+
form,
|
|
286
110
|
{
|
|
287
|
-
|
|
111
|
+
headers: {
|
|
112
|
+
...form.getHeaders(),
|
|
113
|
+
Authorization: token,
|
|
114
|
+
},
|
|
115
|
+
validateStatus: (status) => status < 500,
|
|
288
116
|
}
|
|
289
117
|
);
|
|
290
118
|
|
|
291
|
-
|
|
292
|
-
let primaryCandidates: string[] = [];
|
|
293
|
-
|
|
294
|
-
for (const pattern of primaryPatterns) {
|
|
295
|
-
logger.log(`Searching for primary file with pattern: ${pattern}`);
|
|
296
|
-
const matches = await glob(pattern, {
|
|
297
|
-
cwd: context.cwd,
|
|
298
|
-
nodir: true,
|
|
299
|
-
});
|
|
300
|
-
primaryCandidates.push(
|
|
301
|
-
...matches.map((file) => resolve(context.cwd!, file))
|
|
302
|
-
);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// 过滤出 JAR 文件并与找到的文件列表交叉检查
|
|
306
|
-
primaryCandidates = primaryCandidates
|
|
307
|
-
.filter((file) => file.endsWith('.jar'))
|
|
308
|
-
.filter((file) => jarFiles.includes(file));
|
|
119
|
+
const resData = versionResponse.data;
|
|
309
120
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
`No files matched primaryFileGlob for Modrinth that were also in the main file list.`
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
} else if (jarFiles.length > 1) {
|
|
323
|
-
// 当有多个文件但没有指定 primaryFileGlob 时,需要指定主要文件
|
|
121
|
+
if (versionResponse.status === 200) {
|
|
122
|
+
logger.log(
|
|
123
|
+
`Successfully published to Modrinth: ${resData.project_id} (File ID: ${resData.file_id})`
|
|
124
|
+
);
|
|
125
|
+
return versionResponse.data.id;
|
|
126
|
+
} else if (
|
|
127
|
+
versionResponse.status === 400 ||
|
|
128
|
+
versionResponse.status === 401
|
|
129
|
+
) {
|
|
324
130
|
throw new Error(
|
|
325
|
-
`
|
|
131
|
+
`Failed to publish to Modrinth (${versionResponse.status}): ${resData}`
|
|
132
|
+
);
|
|
133
|
+
} else {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`Failed to publish to Modrinth (${versionResponse.status}): ${resData}`
|
|
326
136
|
);
|
|
327
137
|
}
|
|
328
|
-
// 当只有一个文件时,不设置 primaryFile,让网站做决定
|
|
329
|
-
|
|
330
|
-
return { files: jarFiles, primaryFile };
|
|
331
138
|
}
|