Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ All notable changes to ModShift are documented here. The format follows

## [Unreleased]

### Fixed

- An update that keeps the same version number (a file rebuilt for the target Minecraft
version, e.g. `3.3.6 → 3.3.6`) is now explained in the report instead of looking like an error.

## [0.1.0] - 2026-10-20

First public version.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ https://neyordev.github.io/ModShift/ once GitHub Pages is enabled.
ModShift needs **Node.js 20.17+ or 22.13+**.

```bash
# From npm
# From npm
npm install --global modshift

# From source
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
ModShift needs **Node.js 20.17+ or 22.13+**.

```bash
# From npm (once published)
# From npm
npm install --global modshift

# From source
Expand Down
13 changes: 13 additions & 0 deletions src/core/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ export async function analyzePack(
reason: joinReasons(
idNote,
change && loaderChangeReason(change),
current && rebuildReason(current, best, target),
fallback && fallbackReason(fallback, target),
),
});
Expand Down Expand Up @@ -496,6 +497,18 @@ async function searchReplacements(
return result;
}

// Même numéro de version, autre fichier : l'auteur publie un fichier par version de Minecraft
// (ex. 1.13.2 pour 26.2 puis 1.13.2 pour 26.3). Sans cette précision, « 1.13.2 → 1.13.2 »
// ressemble à une erreur.
function rebuildReason(
current: ModrinthVersion,
best: ModrinthVersion,
target: MigrationTarget,
): string | undefined {
if (current.id === best.id || current.version_number !== best.version_number) return undefined;
return `Same version number, file built for Minecraft ${target.minecraftVersion}.`;
}

function compatLayerReason(hint: CompatLayerHint): string {
return `Its ${getLoader(hint.runs as Loader).name} version could run through ${hint.name} (${COMPAT_LAYER_NOTE}; not added to the pack).`;
}
Expand Down
88 changes: 88 additions & 0 deletions test/core/rebuild.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { describe, expect, it } from 'vitest';
import { analyzePack } from '../../src/core/engine.js';
import type { ModrinthVersion } from '../../src/modrinth/types.js';
import type { ModPack } from '../../src/types.js';
import { renderTable } from '../../src/report/table.js';
import { createFakeClient, loadCatalog } from '../helpers/fakeModrinth.js';

// Cas réel : Packet Fixer, Stella, SkyOcean… publient « 3.3.6 » pour 26.2 puis un autre fichier
// « 3.3.6 » pour 26.3. Le rapport affichait « 3.3.6 → 3.3.6 » sans explication.
function version(id: string, number: string, gameVersion: string, hash: string): ModrinthVersion {
return {
id,
project_id: 'REBUILD1',
name: id,
version_number: number,
game_versions: [gameVersion],
loaders: ['fabric'],
version_type: 'release',
date_published: '2024-09-01T00:00:00Z',
dependencies: [],
status: 'listed',
files: [
{
hashes: { sha1: hash.repeat(20), sha512: hash.repeat(64) },
url: `https://cdn.modrinth.com/data/fixture/${id}.jar`,
filename: `${id}.jar`,
primary: true,
size: 1000,
},
],
};
}

function catalog() {
const base = loadCatalog();
base.projects.push({
id: 'REBUILD1',
slug: 'rebuild-mod',
title: 'Rebuild Mod',
description: 'A mod republished for each Minecraft version.',
categories: ['utility'],
project_type: 'mod',
loaders: ['fabric'],
game_versions: ['1.20.1', '1.21.1'],
downloads: 1000,
});
base.versions.push(
version('v1rebuild-old', '3.3.6', '1.20.1', 'c3'),
version('v1rebuild-new', '3.3.6', '1.21.1', 'c4'),
);
return base;
}

const pack: ModPack = {
source: 'mrpack',
minecraftVersion: '1.20.1',
loader: 'fabric',
mods: [
{
fileName: 'rebuild-mod-3.3.6.jar',
path: 'mods/rebuild-mod-3.3.6.jar',
origin: 'index',
hashes: { sha1: 'c3'.repeat(20) },
metadata: [],
},
],
otherFiles: [],
warnings: [],
};

describe('same version number rebuilt for the target', () => {
it('explains an update that keeps the version number', async () => {
const { client } = createFakeClient(catalog());
const result = await analyzePack(
pack,
{ minecraftVersion: '1.21.1', loader: 'fabric' },
client,
);
const mod = result.mods[0];
expect(mod).toMatchObject({
status: 'update-found',
currentVersion: { id: 'v1rebuild-old', versionNumber: '3.3.6' },
targetVersion: { id: 'v1rebuild-new', versionNumber: '3.3.6' },
reason: 'Same version number, file built for Minecraft 1.21.1.',
});
expect(renderTable(result)).toContain('Same version number, file built for Minecraft 1.21.1.');
});
});
Loading