mirror of
https://github.com/sp-tarkov/forge.git
synced 2025-02-13 04:30:41 -05:00
Adds Mod Version Dependency System
Pretty nifty, but it still needs a few things before merge. Factory & front-end work, at least.
This commit is contained in:
parent
297a58cba1
commit
74f61df875
@ -16,6 +16,8 @@ use Illuminate\Support\Str;
|
|||||||
use Laravel\Scout\Searchable;
|
use Laravel\Scout\Searchable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $name
|
||||||
* @property string $slug
|
* @property string $slug
|
||||||
*/
|
*/
|
||||||
class Mod extends Model
|
class Mod extends Model
|
||||||
|
40
app/Models/ModDependency.php
Normal file
40
app/Models/ModDependency.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $mod_version_id
|
||||||
|
* @property int $dependency_mod_id
|
||||||
|
* @property string $version_constraint
|
||||||
|
* @property int|null $resolved_version_id
|
||||||
|
*/
|
||||||
|
class ModDependency extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The relationship between a mod dependency and mod version.
|
||||||
|
*/
|
||||||
|
public function modVersion(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ModVersion::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The relationship between a mod dependency and mod.
|
||||||
|
*/
|
||||||
|
public function dependencyMod(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Mod::class, 'dependency_mod_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The relationship between a mod dependency and resolved mod version.
|
||||||
|
*/
|
||||||
|
public function resolvedVersion(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ModVersion::class, 'resolved_version_id');
|
||||||
|
}
|
||||||
|
}
|
@ -6,8 +6,14 @@ use App\Models\Scopes\DisabledScope;
|
|||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $mod_id
|
||||||
|
* @property string $version
|
||||||
|
*/
|
||||||
class ModVersion extends Model
|
class ModVersion extends Model
|
||||||
{
|
{
|
||||||
use HasFactory, SoftDeletes;
|
use HasFactory, SoftDeletes;
|
||||||
@ -22,6 +28,14 @@ class ModVersion extends Model
|
|||||||
return $this->belongsTo(Mod::class);
|
return $this->belongsTo(Mod::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The relationship between a mod version and its dependencies.
|
||||||
|
*/
|
||||||
|
public function dependencies(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(ModDependency::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function sptVersion(): BelongsTo
|
public function sptVersion(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(SptVersion::class);
|
return $this->belongsTo(SptVersion::class);
|
||||||
|
33
app/Observers/ModDependencyObserver.php
Normal file
33
app/Observers/ModDependencyObserver.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Observers;
|
||||||
|
|
||||||
|
use App\Models\ModDependency;
|
||||||
|
use App\Models\ModVersion;
|
||||||
|
use App\Services\ModVersionService;
|
||||||
|
|
||||||
|
class ModDependencyObserver
|
||||||
|
{
|
||||||
|
protected ModVersionService $modVersionService;
|
||||||
|
|
||||||
|
public function __construct(ModVersionService $modVersionService)
|
||||||
|
{
|
||||||
|
$this->modVersionService = $modVersionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function saved(ModDependency $modDependency): void
|
||||||
|
{
|
||||||
|
$modVersion = ModVersion::find($modDependency->mod_version_id);
|
||||||
|
if ($modVersion) {
|
||||||
|
$this->modVersionService->resolveDependencies($modVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleted(ModDependency $modDependency): void
|
||||||
|
{
|
||||||
|
$modVersion = ModVersion::find($modDependency->mod_version_id);
|
||||||
|
if ($modVersion) {
|
||||||
|
$this->modVersionService->resolveDependencies($modVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
app/Observers/ModVersionObserver.php
Normal file
33
app/Observers/ModVersionObserver.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Observers;
|
||||||
|
|
||||||
|
use App\Models\ModDependency;
|
||||||
|
use App\Models\ModVersion;
|
||||||
|
use App\Services\ModVersionService;
|
||||||
|
|
||||||
|
class ModVersionObserver
|
||||||
|
{
|
||||||
|
protected ModVersionService $modVersionService;
|
||||||
|
|
||||||
|
public function __construct(ModVersionService $modVersionService)
|
||||||
|
{
|
||||||
|
$this->modVersionService = $modVersionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function saved(ModVersion $modVersion): void
|
||||||
|
{
|
||||||
|
$dependencies = ModDependency::where('resolved_version_id', $modVersion->id)->get();
|
||||||
|
foreach ($dependencies as $dependency) {
|
||||||
|
$this->modVersionService->resolveDependencies($dependency->modVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleted(ModVersion $modVersion): void
|
||||||
|
{
|
||||||
|
$dependencies = ModDependency::where('resolved_version_id', $modVersion->id)->get();
|
||||||
|
foreach ($dependencies as $dependency) {
|
||||||
|
$this->modVersionService->resolveDependencies($dependency->modVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,11 @@
|
|||||||
|
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Models\ModDependency;
|
||||||
|
use App\Models\ModVersion;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Observers\ModDependencyObserver;
|
||||||
|
use App\Observers\ModVersionObserver;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
@ -25,6 +29,10 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
// Allow mass assignment for all models. Be careful!
|
// Allow mass assignment for all models. Be careful!
|
||||||
Model::unguard();
|
Model::unguard();
|
||||||
|
|
||||||
|
// Register observers.
|
||||||
|
ModVersion::observe(ModVersionObserver::class);
|
||||||
|
ModDependency::observe(ModDependencyObserver::class);
|
||||||
|
|
||||||
// This gate determines who can access the Pulse dashboard.
|
// This gate determines who can access the Pulse dashboard.
|
||||||
Gate::define('viewPulse', function (User $user) {
|
Gate::define('viewPulse', function (User $user) {
|
||||||
return $user->isAdmin();
|
return $user->isAdmin();
|
||||||
|
59
app/Services/ModVersionService.php
Normal file
59
app/Services/ModVersionService.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\ModVersion;
|
||||||
|
use Composer\Semver\Semver;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class ModVersionService
|
||||||
|
{
|
||||||
|
// TODO: This works, but it needs to be refactored. It's too big and does too much.
|
||||||
|
public function resolveDependencies(ModVersion $modVersion): array
|
||||||
|
{
|
||||||
|
$resolvedVersions = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Eager load dependencies with related mod versions
|
||||||
|
$dependencies = $modVersion->dependencies()->with(['dependencyMod.versions'])->get();
|
||||||
|
|
||||||
|
foreach ($dependencies as $dependency) {
|
||||||
|
$dependencyMod = $dependency->dependencyMod;
|
||||||
|
|
||||||
|
// Ensure dependencyMod exists and has versions
|
||||||
|
if (! $dependencyMod || $dependencyMod->versions->isEmpty()) {
|
||||||
|
if ($dependency->resolved_version_id !== null) {
|
||||||
|
$dependency->updateQuietly(['resolved_version_id' => null]);
|
||||||
|
}
|
||||||
|
$resolvedVersions[$dependency->id] = null;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get available versions in the form ['version' => 'id']
|
||||||
|
$availableVersions = $dependencyMod->versions->pluck('id', 'version')->toArray();
|
||||||
|
|
||||||
|
// Find the latest version that satisfies the constraint
|
||||||
|
$satisfyingVersions = Semver::satisfiedBy(array_keys($availableVersions), $dependency->version_constraint);
|
||||||
|
|
||||||
|
// Get the first element's id from satisfyingVersions
|
||||||
|
$latestVersionId = $satisfyingVersions ? $availableVersions[reset($satisfyingVersions)] : null;
|
||||||
|
|
||||||
|
// Update the resolved version ID in the ModDependency record
|
||||||
|
if ($dependency->resolved_version_id !== $latestVersionId) {
|
||||||
|
$dependency->updateQuietly(['resolved_version_id' => $latestVersionId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the resolved ModVersion to the array (or null if not found)
|
||||||
|
$resolvedVersions[$dependency->id] = $latestVersionId ? ModVersion::find($latestVersionId) : null;
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error resolving dependencies for ModVersion: '.$modVersion->id, [
|
||||||
|
'exception' => $e->getMessage(),
|
||||||
|
'mod_version_id' => $modVersion->id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $resolvedVersions;
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@
|
|||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
"ext-intl": "*",
|
"ext-intl": "*",
|
||||||
"aws/aws-sdk-php": "^3.314",
|
"aws/aws-sdk-php": "^3.314",
|
||||||
|
"composer/semver": "^3.4",
|
||||||
"filament/filament": "^3.2",
|
"filament/filament": "^3.2",
|
||||||
"http-interop/http-factory-guzzle": "^1.2",
|
"http-interop/http-factory-guzzle": "^1.2",
|
||||||
"laravel/framework": "^11.11",
|
"laravel/framework": "^11.11",
|
||||||
|
83
composer.lock
generated
83
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "93542851cf4f8ca963cbb447d144300e",
|
"content-hash": "920d8caa63c8b0da280a78c05d5983a8",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "anourvalar/eloquent-serialize",
|
"name": "anourvalar/eloquent-serialize",
|
||||||
@ -620,6 +620,87 @@
|
|||||||
],
|
],
|
||||||
"time": "2023-12-20T15:40:13+00:00"
|
"time": "2023-12-20T15:40:13+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "composer/semver",
|
||||||
|
"version": "3.4.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/composer/semver.git",
|
||||||
|
"reference": "c51258e759afdb17f1fd1fe83bc12baaef6309d6"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/composer/semver/zipball/c51258e759afdb17f1fd1fe83bc12baaef6309d6",
|
||||||
|
"reference": "c51258e759afdb17f1fd1fe83bc12baaef6309d6",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^5.3.2 || ^7.0 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "^1.4",
|
||||||
|
"symfony/phpunit-bridge": "^4.2 || ^5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Composer\\Semver\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nils Adermann",
|
||||||
|
"email": "naderman@naderman.de",
|
||||||
|
"homepage": "http://www.naderman.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jordi Boggiano",
|
||||||
|
"email": "j.boggiano@seld.be",
|
||||||
|
"homepage": "http://seld.be"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rob Bast",
|
||||||
|
"email": "rob.bast@gmail.com",
|
||||||
|
"homepage": "http://robbast.nl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Semver library that offers utilities, version constraint parsing and validation.",
|
||||||
|
"keywords": [
|
||||||
|
"semantic",
|
||||||
|
"semver",
|
||||||
|
"validation",
|
||||||
|
"versioning"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"irc": "ircs://irc.libera.chat:6697/composer",
|
||||||
|
"issues": "https://github.com/composer/semver/issues",
|
||||||
|
"source": "https://github.com/composer/semver/tree/3.4.2"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://packagist.com",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/composer",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-07-12T11:35:52+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "danharrin/date-format-converter",
|
"name": "danharrin/date-format-converter",
|
||||||
"version": "v0.3.1",
|
"version": "v0.3.1",
|
||||||
|
@ -30,12 +30,21 @@ class ModFactory extends Factory
|
|||||||
'featured' => fake()->boolean(),
|
'featured' => fake()->boolean(),
|
||||||
'contains_ai_content' => fake()->boolean(),
|
'contains_ai_content' => fake()->boolean(),
|
||||||
'contains_ads' => fake()->boolean(),
|
'contains_ads' => fake()->boolean(),
|
||||||
'disabled' => fake()->boolean(),
|
|
||||||
'created_at' => now(),
|
'created_at' => now(),
|
||||||
'updated_at' => now(),
|
'updated_at' => now(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate that the mod should be disabled.
|
||||||
|
*/
|
||||||
|
public function disabled(): static
|
||||||
|
{
|
||||||
|
return $this->state(fn (array $attributes) => [
|
||||||
|
'disabled' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicate that the mod should be soft-deleted.
|
* Indicate that the mod should be soft-deleted.
|
||||||
*/
|
*/
|
||||||
|
@ -22,9 +22,18 @@ class ModVersionFactory extends Factory
|
|||||||
'spt_version_id' => SptVersion::factory(),
|
'spt_version_id' => SptVersion::factory(),
|
||||||
'virus_total_link' => fake()->url(),
|
'virus_total_link' => fake()->url(),
|
||||||
'downloads' => fake()->randomNumber(),
|
'downloads' => fake()->randomNumber(),
|
||||||
'disabled' => fake()->boolean(),
|
|
||||||
'created_at' => Carbon::now()->subDays(rand(0, 365))->subHours(rand(0, 23)),
|
'created_at' => Carbon::now()->subDays(rand(0, 365))->subHours(rand(0, 23)),
|
||||||
'updated_at' => Carbon::now()->subDays(rand(0, 365))->subHours(rand(0, 23)),
|
'updated_at' => Carbon::now()->subDays(rand(0, 365))->subHours(rand(0, 23)),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicate that the mod version should be disabled.
|
||||||
|
*/
|
||||||
|
public function disabled(): static
|
||||||
|
{
|
||||||
|
return $this->state(fn (array $attributes) => [
|
||||||
|
'disabled' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('mod_dependencies', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('mod_version_id')
|
||||||
|
->constrained('mod_versions')
|
||||||
|
->cascadeOnDelete()
|
||||||
|
->cascadeOnUpdate();
|
||||||
|
$table->foreignId('dependency_mod_id')
|
||||||
|
->constrained('mods')
|
||||||
|
->cascadeOnDelete()
|
||||||
|
->cascadeOnUpdate();
|
||||||
|
$table->string('version_constraint'); // e.g., ^1.0.1
|
||||||
|
$table->foreignId('resolved_version_id')
|
||||||
|
->nullable()
|
||||||
|
->constrained('mod_versions')
|
||||||
|
->nullOnDelete()
|
||||||
|
->cascadeOnUpdate();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('mod_dependencies');
|
||||||
|
}
|
||||||
|
};
|
236
tests/Feature/ModDependencyTest.php
Normal file
236
tests/Feature/ModDependencyTest.php
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Mod;
|
||||||
|
use App\Models\ModDependency;
|
||||||
|
use App\Models\ModVersion;
|
||||||
|
|
||||||
|
it('resolves mod version dependency when mod version is created', function () {
|
||||||
|
$modA = Mod::factory()->create(['name' => 'Mod A']);
|
||||||
|
$modB = Mod::factory()->create(['name' => 'Mod B']);
|
||||||
|
|
||||||
|
// Create versions for Mod B
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.0.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.1']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '2.0.0']);
|
||||||
|
|
||||||
|
// Create versions for Mod A that depends on Mod B
|
||||||
|
$modAv1 = ModVersion::factory()->create(['mod_id' => $modA->id, 'version' => '1.0.0']);
|
||||||
|
$modDependency = ModDependency::create([
|
||||||
|
'mod_version_id' => $modAv1->id,
|
||||||
|
'dependency_mod_id' => $modB->id,
|
||||||
|
'version_constraint' => '^1.0.0',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$modDependency->refresh();
|
||||||
|
expect($modDependency->resolvedVersion->version)->toBe('1.1.1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resolves mod version dependency when mod version is updated', function () {
|
||||||
|
$modA = Mod::factory()->create(['name' => 'Mod A']);
|
||||||
|
$modB = Mod::factory()->create(['name' => 'Mod B']);
|
||||||
|
|
||||||
|
// Create versions for Mod B
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.0.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.0']);
|
||||||
|
$modBv3 = ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.1']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '2.0.0']);
|
||||||
|
|
||||||
|
// Create versions for Mod A that depends on Mod B
|
||||||
|
$modAv1 = ModVersion::factory()->create(['mod_id' => $modA->id, 'version' => '1.0.0']);
|
||||||
|
$modDependency = ModDependency::create([
|
||||||
|
'mod_version_id' => $modAv1->id,
|
||||||
|
'dependency_mod_id' => $modB->id,
|
||||||
|
'version_constraint' => '^1.0.0',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$modDependency->refresh();
|
||||||
|
expect($modDependency->resolvedVersion->version)->toBe('1.1.1');
|
||||||
|
|
||||||
|
// Update the mod B version
|
||||||
|
$modBv3->update(['version' => '1.1.2']);
|
||||||
|
|
||||||
|
$modDependency->refresh();
|
||||||
|
expect($modDependency->resolvedVersion->version)->toBe('1.1.2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resolves mod version dependency when mod version is deleted', function () {
|
||||||
|
$modA = Mod::factory()->create(['name' => 'Mod A']);
|
||||||
|
$modB = Mod::factory()->create(['name' => 'Mod B']);
|
||||||
|
|
||||||
|
// Create versions for Mod B
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.0.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.0']);
|
||||||
|
$modBv3 = ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.1']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '2.0.0']);
|
||||||
|
|
||||||
|
// Create versions for Mod A that depends on Mod B
|
||||||
|
$modAv1 = ModVersion::factory()->create(['mod_id' => $modA->id, 'version' => '1.0.0']);
|
||||||
|
$modDependency = ModDependency::create([
|
||||||
|
'mod_version_id' => $modAv1->id,
|
||||||
|
'dependency_mod_id' => $modB->id,
|
||||||
|
'version_constraint' => '^1.0.0',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$modDependency->refresh();
|
||||||
|
expect($modDependency->resolvedVersion->version)->toBe('1.1.1');
|
||||||
|
|
||||||
|
// Update the mod B version
|
||||||
|
$modBv3->delete();
|
||||||
|
|
||||||
|
$modDependency->refresh();
|
||||||
|
expect($modDependency->resolvedVersion->version)->toBe('1.1.0');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resolves mod version dependency after semantic version constraint is updated', function () {
|
||||||
|
$modA = Mod::factory()->create(['name' => 'Mod A']);
|
||||||
|
$modB = Mod::factory()->create(['name' => 'Mod B']);
|
||||||
|
|
||||||
|
// Create versions for Mod B
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.0.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.1']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '2.0.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '2.0.1']);
|
||||||
|
|
||||||
|
// Create versions for Mod A that depends on Mod B
|
||||||
|
$modAv1 = ModVersion::factory()->create(['mod_id' => $modA->id, 'version' => '1.0.0']);
|
||||||
|
$modDependency = ModDependency::create([
|
||||||
|
'mod_version_id' => $modAv1->id,
|
||||||
|
'dependency_mod_id' => $modB->id,
|
||||||
|
'version_constraint' => '^1.0.0',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$modDependency->refresh();
|
||||||
|
expect($modDependency->resolvedVersion->version)->toBe('1.1.1');
|
||||||
|
|
||||||
|
// Update the dependency version constraint
|
||||||
|
$modDependency->update(['version_constraint' => '^2.0.0']);
|
||||||
|
|
||||||
|
$modDependency->refresh();
|
||||||
|
expect($modDependency->resolvedVersion->version)->toBe('2.0.1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resolves mod version dependency with exact semantic version constraint', function () {
|
||||||
|
$modA = Mod::factory()->create(['name' => 'Mod A']);
|
||||||
|
$modB = Mod::factory()->create(['name' => 'Mod B']);
|
||||||
|
|
||||||
|
// Create versions for Mod B
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.0.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.1']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '2.0.0']);
|
||||||
|
|
||||||
|
// Create versions for Mod A that depends on Mod B
|
||||||
|
$modAv1 = ModVersion::factory()->create(['mod_id' => $modA->id, 'version' => '1.0.0']);
|
||||||
|
$modDependency = ModDependency::create([
|
||||||
|
'mod_version_id' => $modAv1->id,
|
||||||
|
'dependency_mod_id' => $modB->id,
|
||||||
|
'version_constraint' => '1.1.0',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$modDependency->refresh();
|
||||||
|
expect($modDependency->resolvedVersion->version)->toBe('1.1.0');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resolves mod version dependency with complex semantic version constraint', function () {
|
||||||
|
$modA = Mod::factory()->create(['name' => 'Mod A']);
|
||||||
|
$modB = Mod::factory()->create(['name' => 'Mod B']);
|
||||||
|
|
||||||
|
// Create versions for Mod B
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.0.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.1']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.2.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.2.1']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '2.0.0']);
|
||||||
|
|
||||||
|
// Create versions for Mod A that depends on Mod B
|
||||||
|
$modAv1 = ModVersion::factory()->create(['mod_id' => $modA->id, 'version' => '1.0.0']);
|
||||||
|
$modDependency = ModDependency::create([
|
||||||
|
'mod_version_id' => $modAv1->id,
|
||||||
|
'dependency_mod_id' => $modB->id,
|
||||||
|
'version_constraint' => '>=1.0.0 <2.0.0',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$modDependency->refresh();
|
||||||
|
expect($modDependency->resolvedVersion->version)->toBe('1.2.1');
|
||||||
|
|
||||||
|
$modDependency->update(['version_constraint' => '1.0.0 || >=1.1.0 <1.2.0']);
|
||||||
|
|
||||||
|
$modDependency->refresh();
|
||||||
|
expect($modDependency->resolvedVersion->version)->toBe('1.1.1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resolves null when no mod versions are available', function () {
|
||||||
|
$modA = Mod::factory()->create(['name' => 'Mod A']);
|
||||||
|
$modB = Mod::factory()->create(['name' => 'Mod B']);
|
||||||
|
|
||||||
|
// Create version for Mod A that has no resolvable dependency
|
||||||
|
$modAv1 = ModVersion::factory()->create(['mod_id' => $modA->id, 'version' => '1.0.0']);
|
||||||
|
$modDependency = ModDependency::create([
|
||||||
|
'mod_version_id' => $modAv1->id,
|
||||||
|
'dependency_mod_id' => $modB->id,
|
||||||
|
'version_constraint' => '^1.0.0',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$modDependency->refresh();
|
||||||
|
expect($modDependency->resolved_version_id)->toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resolves null when no mod versions match against semantic version constraint', function () {
|
||||||
|
$modA = Mod::factory()->create(['name' => 'Mod A']);
|
||||||
|
$modB = Mod::factory()->create(['name' => 'Mod B']);
|
||||||
|
|
||||||
|
// Create versions for Mod B
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.0.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '2.0.0']);
|
||||||
|
|
||||||
|
// Create version for Mod A that has no resolvable dependency
|
||||||
|
$modAv1 = ModVersion::factory()->create(['mod_id' => $modA->id, 'version' => '1.0.0']);
|
||||||
|
$modDependency = ModDependency::create([
|
||||||
|
'mod_version_id' => $modAv1->id,
|
||||||
|
'dependency_mod_id' => $modB->id,
|
||||||
|
'version_constraint' => '~1.2.0',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$modDependency->refresh();
|
||||||
|
expect($modDependency->resolved_version_id)->toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resolves multiple dependencies', function () {
|
||||||
|
$modA = Mod::factory()->create(['name' => 'Mod A']);
|
||||||
|
$modB = Mod::factory()->create(['name' => 'Mod B']);
|
||||||
|
$modC = Mod::factory()->create(['name' => 'Mod C']);
|
||||||
|
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.0.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '1.1.1']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modB->id, 'version' => '2.0.0']);
|
||||||
|
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modC->id, 'version' => '1.0.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modC->id, 'version' => '1.1.0']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modC->id, 'version' => '1.1.1']);
|
||||||
|
ModVersion::factory()->create(['mod_id' => $modC->id, 'version' => '2.0.0']);
|
||||||
|
|
||||||
|
// Creating a version for Mod A that depends on Mod B and Mod C
|
||||||
|
$modAv1 = ModVersion::factory()->create(['mod_id' => $modA->id, 'version' => '1.0.0']);
|
||||||
|
|
||||||
|
$modDependencyB = ModDependency::create([
|
||||||
|
'mod_version_id' => $modAv1->id,
|
||||||
|
'dependency_mod_id' => $modB->id,
|
||||||
|
'version_constraint' => '^1.0.0',
|
||||||
|
]);
|
||||||
|
$modDependencyC = ModDependency::create([
|
||||||
|
'mod_version_id' => $modAv1->id,
|
||||||
|
'dependency_mod_id' => $modC->id,
|
||||||
|
'version_constraint' => '^1.0.0',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$modDependencyB->refresh();
|
||||||
|
expect($modDependencyB->resolvedVersion->version)->toBe('1.1.1');
|
||||||
|
|
||||||
|
$modDependencyC->refresh();
|
||||||
|
expect($modDependencyC->resolvedVersion->version)->toBe('1.1.1');
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user