From 7f403800caa94763a0ef83f471a21533fd73b327 Mon Sep 17 00:00:00 2001 From: William Allen Date: Tue, 27 Jan 2026 11:13:19 -0500 Subject: [PATCH] Move `buildfailuredetails` to `buildfailure` table The `buildfailuredetails` table is used to deduplicate recurring build failures. In practice, both of these tables are several orders of magnitude smaller than the build2test and testoutput tables, and deduplicating errors doesn't save much space. The crc32-based deduplication process is also problematic due to the low entropy hash function and need for relatively complex logic when inserting new records. This commit simplifies the schema by merging the columns of the `buildfailuredetails` table into the `buildfailure` table, bringing it in line with the similar `builderror` table. Follow-up work will merge the `builderror` and `buildfailure` tables. --- app/Console/Commands/CleanDatabase.php | 1 - app/Http/Controllers/BuildController.php | 2 +- .../Controllers/BuildPropertiesController.php | 5 +- app/Models/RichBuildAlert.php | 29 +++--- app/Models/RichBuildAlertDetails.php | 53 ---------- app/Utils/DatabaseCleanupUtils.php | 9 -- app/Utils/SubmissionUtils.php | 96 +++++++++++-------- app/cdash/app/Model/Build.php | 73 +++++++------- app/cdash/app/Model/BuildFailure.php | 41 +++----- app/cdash/tests/test_buildfailuredetails.php | 18 +--- app/cdash/tests/test_buildmodel.php | 10 +- app/cdash/tests/test_removebuilds.php | 19 +--- ...ldfailuredetails_to_buildfailure_table.php | 57 +++++++++++ phpstan-baseline.neon | 77 ++------------- 14 files changed, 201 insertions(+), 289 deletions(-) delete mode 100644 app/Models/RichBuildAlertDetails.php create mode 100644 database/migrations/2026_01_27_131726_move_buildfailuredetails_to_buildfailure_table.php diff --git a/app/Console/Commands/CleanDatabase.php b/app/Console/Commands/CleanDatabase.php index 4bd8e5f20b..5f47830394 100644 --- a/app/Console/Commands/CleanDatabase.php +++ b/app/Console/Commands/CleanDatabase.php @@ -27,7 +27,6 @@ public function handle(): void // Reconfigure laravel to log to stderr for the rest of this command. config(['logging.default' => 'stderr']); - DatabaseCleanupUtils::deleteUnusedRows('buildfailuredetails', 'id', 'buildfailure', 'detailsid'); DatabaseCleanupUtils::deleteUnusedRows('configure', 'id', 'build2configure', 'configureid'); DatabaseCleanupUtils::deleteUnusedRows('coveragefile', 'id', 'coverage', 'fileid'); DatabaseCleanupUtils::deleteUnusedRows('note', 'id', 'build2note', 'noteid'); diff --git a/app/Http/Controllers/BuildController.php b/app/Http/Controllers/BuildController.php index 667fcefb78..45b3450c5e 100644 --- a/app/Http/Controllers/BuildController.php +++ b/app/Http/Controllers/BuildController.php @@ -934,7 +934,7 @@ public function apiViewBuildError(): JsonResponse // Build failure table $resolvedBuildFailures = $this->build->GetResolvedBuildFailures($type); - while ($resolvedBuildFailure = $resolvedBuildFailures->fetch()) { + foreach ($resolvedBuildFailures as $resolvedBuildFailure) { $marshaledResolvedBuildFailure = BuildFailure::marshal($resolvedBuildFailure, $this->project, $revision, false, $buildfailure); if ($this->project->DisplayLabels) { diff --git a/app/Http/Controllers/BuildPropertiesController.php b/app/Http/Controllers/BuildPropertiesController.php index 9876b18df2..b68d9a1a67 100644 --- a/app/Http/Controllers/BuildPropertiesController.php +++ b/app/Http/Controllers/BuildPropertiesController.php @@ -233,10 +233,9 @@ private function get_defects_for_builds() buildid IN $placeholder_str"; // Query buildfailure table. $sql2 = - "SELECT bf.buildid, bfd.stderror AS descr + "SELECT bf.buildid, bf.stderror AS descr FROM buildfailure bf - JOIN buildfailuredetails bfd ON bf.detailsid = bfd.id - WHERE bfd.type = $type AND + WHERE bf.type = $type AND bf.buildid IN $placeholder_str"; } elseif ($defect === 'testfailed') { $valid_defect = true; diff --git a/app/Models/RichBuildAlert.php b/app/Models/RichBuildAlert.php index 0a24521ecb..04f2a9b191 100644 --- a/app/Models/RichBuildAlert.php +++ b/app/Models/RichBuildAlert.php @@ -6,15 +6,21 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Database\Eloquent\Relations\HasOne; /** * @property int $id * @property int $buildid - * @property int $detailsid * @property string $workingdirectory * @property string $sourcefile * @property int $newstatus + * @property int $type + * @property string $stdoutput + * @property string $stderror + * @property string $exitcondition + * @property string $language + * @property string $targetname + * @property string $outputfile + * @property string $outputtype * * @mixin Builder */ @@ -26,17 +32,24 @@ class RichBuildAlert extends Model protected $fillable = [ 'buildid', - 'detailsid', 'workingdirectory', 'sourcefile', 'newstatus', + 'type', + 'stdoutput', + 'stderror', + 'exitcondition', + 'language', + 'targetname', + 'outputfile', + 'outputtype', ]; protected $casts = [ 'id' => 'integer', 'buildid' => 'integer', - 'detailsid' => 'integer', 'newstatus' => 'integer', + 'type' => 'integer', ]; /** @@ -47,14 +60,6 @@ public function build(): BelongsTo return $this->belongsTo(Build::class, 'buildid'); } - /** - * @return HasOne - */ - public function details(): HasOne - { - return $this->hasOne(RichBuildAlertDetails::class, 'id', 'detailsid'); - } - /** * @return BelongsToMany */ diff --git a/app/Models/RichBuildAlertDetails.php b/app/Models/RichBuildAlertDetails.php deleted file mode 100644 index b70e995125..0000000000 --- a/app/Models/RichBuildAlertDetails.php +++ /dev/null @@ -1,53 +0,0 @@ - - */ -class RichBuildAlertDetails extends Model -{ - protected $table = 'buildfailuredetails'; - - public $timestamps = false; - - protected $fillable = [ - 'type', - 'stdoutput', - 'stderror', - 'exitcondition', - 'language', - 'targetname', - 'outputfile', - 'outputtype', - 'crc32', - ]; - - protected $casts = [ - 'type' => 'integer', - 'crc32' => 'integer', - ]; - - /** - * @return HasManyThrough - */ - public function builds(): HasManyThrough - { - return $this->hasManyThrough(Build::class, RichBuildAlert::class, 'detailsid', 'id', 'id', 'buildid'); - } -} diff --git a/app/Utils/DatabaseCleanupUtils.php b/app/Utils/DatabaseCleanupUtils.php index 0960d9713a..d5820af9f7 100644 --- a/app/Utils/DatabaseCleanupUtils.php +++ b/app/Utils/DatabaseCleanupUtils.php @@ -11,7 +11,6 @@ use App\Models\CoverageFile; use App\Models\Image; use App\Models\Note; -use App\Models\RichBuildAlertDetails; use App\Models\Test; use App\Models\UploadFile; use CDash\Database; @@ -134,14 +133,6 @@ public static function removeBuild($buildid): void // Use Eloquent relationships to delete shared records that are only // used by builds that are about to be deleted. - // buildfailuredetails - RichBuildAlertDetails::whereHas('builds', function (Builder $query) use ($buildids): void { - $query->whereIn('build.id', $buildids); - }) - ->whereDoesntHave('builds', function (Builder $query) use ($buildids): void { - $query->whereNotIn('build.id', $buildids); - })->delete(); - // configure Configure::whereHas('builds', function (Builder $query) use ($buildids): void { $query->whereIn('id', $buildids); diff --git a/app/Utils/SubmissionUtils.php b/app/Utils/SubmissionUtils.php index a0bf4b78b9..07590e767a 100644 --- a/app/Utils/SubmissionUtils.php +++ b/app/Utils/SubmissionUtils.php @@ -18,7 +18,6 @@ use App\Http\Submission\Handlers\TestingJUnitHandler; use App\Http\Submission\Handlers\UpdateHandler; use App\Http\Submission\Handlers\UploadHandler; -use App\Models\RichBuildAlert; use CDash\Database; use CDash\Model\Build; use CDash\Model\BuildUpdate; @@ -157,7 +156,6 @@ public static function compute_error_difference($buildid, $previousbuildid, $war $pdo = Database::getInstance()->getPdo(); $build = \App\Models\Build::findOrFail((int) $buildid); - $previous_build = \App\Models\Build::findOrFail((int) $previousbuildid); // Look at the difference positive and negative test errors DB::update(' @@ -182,29 +180,30 @@ public static function compute_error_difference($buildid, $previousbuildid, $war 'previousbuildid' => $previousbuildid, ]); - // Recurring buildfailures are represented by the buildfailuredetails table. - // Get a list of buildfailuredetails IDs for the current build and the - // previous build. - - $current_failures = $build->richAlerts() - ->whereRelation('details', 'type', $warning) - ->pluck('detailsid')->toArray(); - - $previous_failures = $previous_build->richAlerts() - ->whereRelation('details', 'type', $warning) - ->pluck('detailsid')->toArray(); - - // Check if any of these are new failures and mark them accordingly. - foreach ($current_failures as $failure) { - if (!in_array($failure, $previous_failures)) { - RichBuildAlert::where([ - 'buildid' => $buildid, - 'detailsid' => $failure, - ])->update([ - 'newstatus' => 1, - ]); - } - } + DB::update(' + UPDATE buildfailure + SET newstatus=1 + WHERE + buildid = :buildid + AND type = :type + AND NOT EXISTS( + SELECT * + FROM buildfailure buildfailure_previous + WHERE + buildfailure_previous.buildid = :previousbuildid + AND buildfailure_previous.type = buildfailure.type + AND buildfailure_previous.stderror = buildfailure.stderror + AND buildfailure_previous.sourcefile = buildfailure.sourcefile + AND buildfailure_previous.targetname = buildfailure.targetname + AND buildfailure_previous.language = buildfailure.language + AND buildfailure_previous.outputfile = buildfailure.outputfile + AND buildfailure_previous.outputtype = buildfailure.outputtype + ) + ', [ + 'buildid' => $buildid, + 'type' => $warning, + 'previousbuildid' => $previousbuildid, + ]); // Maybe we can get that from the query (don't know). $npositives = $build->basicAlerts() @@ -213,13 +212,13 @@ public static function compute_error_difference($buildid, $previousbuildid, $war ->count(); $npositives += $build->richAlerts() + ->where('type', $warning) ->where('newstatus', 1) - ->whereRelation('details', 'type', $warning) ->count(); // Count how many build defects were fixed since the previous build. - $stmt = $pdo->prepare(' - SELECT COUNT(*) + $nnegatives = DB::select(' + SELECT COUNT(*) AS c FROM builderror builderror_previous WHERE builderror_previous.buildid = :previousbuildid @@ -234,19 +233,36 @@ public static function compute_error_difference($buildid, $previousbuildid, $war AND builderror_previous.sourcefile = builderror.sourcefile AND builderror_previous.sourceline = builderror.sourceline ) - '); - $stmt->bindValue(':buildid', $buildid); - $stmt->bindValue(':previousbuildid', $previousbuildid); - $stmt->bindValue(':type', $warning); - pdo_execute($stmt); - $negatives_array = $stmt->fetch(); - $nnegatives = $negatives_array[0]; + ', [ + 'buildid' => $buildid, + 'type' => $warning, + 'previousbuildid' => $previousbuildid, + ])[0]->c; - foreach ($previous_failures as $failure) { - if (!in_array($failure, $current_failures)) { - $nnegatives++; - } - } + $nnegatives += DB::select(' + SELECT COUNT(*) AS c + FROM buildfailure buildfailure_previous + WHERE + buildfailure_previous.buildid = :previousbuildid + AND buildfailure_previous.type = :type + AND NOT EXISTS( + SELECT * + FROM buildfailure + WHERE + buildfailure.buildid = :buildid + AND buildfailure_previous.type = buildfailure.type + AND buildfailure_previous.stderror = buildfailure.stderror + AND buildfailure_previous.sourcefile = buildfailure.sourcefile + AND buildfailure_previous.targetname = buildfailure.targetname + AND buildfailure_previous.language = buildfailure.language + AND buildfailure_previous.outputfile = buildfailure.outputfile + AND buildfailure_previous.outputtype = buildfailure.outputtype + ) + ', [ + 'buildid' => $buildid, + 'type' => $warning, + 'previousbuildid' => $previousbuildid, + ])[0]->c; // Check if a diff already exists for this build. DB::beginTransaction(); diff --git a/app/cdash/app/Model/Build.php b/app/cdash/app/Model/Build.php index e62449b640..2779057653 100644 --- a/app/cdash/app/Model/Build.php +++ b/app/cdash/app/Model/Build.php @@ -664,28 +664,32 @@ protected function PropertyFilter(array $rows, array $filters): array * * @todo This doesn't support getting resolved build failures across parent builds. **/ - public function GetResolvedBuildFailures(int $type): PDOStatement + public function GetResolvedBuildFailures(int $type): array { - $currentFailuresQuery = - 'SELECT bf.detailsid FROM buildfailure AS bf - LEFT JOIN buildfailuredetails AS bfd ON (bf.detailsid=bfd.id) - WHERE bf.buildid = :id AND bfd.type = :type'; - - $stmt = $this->PDO->prepare( - "SELECT bf.id, bfd.language, bf.sourcefile, bfd.targetname, - bfd.outputfile, bfd.outputtype, bf.workingdirectory, - bfd.stderror, bfd.stdoutput, bfd.exitcondition - FROM buildfailure AS bf - LEFT JOIN buildfailuredetails AS bfd ON (bfd.id=bf.detailsid) - WHERE bf.buildid = :previousid - AND bfd.type = :type - AND bfd.id NOT IN ($currentFailuresQuery)" - ); - $stmt->bindValue(':id', $this->Id); - $stmt->bindValue(':type', $type); - $stmt->bindValue(':previousid', $this->GetPreviousBuildId()); - pdo_execute($stmt); - return $stmt; + return DB::select(' + SELECT buildfailure_previous.* + FROM buildfailure buildfailure_previous + WHERE + buildfailure_previous.buildid = :previousbuildid + AND buildfailure_previous.type = :type + AND NOT EXISTS( + SELECT * + FROM buildfailure + WHERE + buildfailure.buildid = :buildid + AND buildfailure_previous.type = buildfailure.type + AND buildfailure_previous.stderror = buildfailure.stderror + AND buildfailure_previous.sourcefile = buildfailure.sourcefile + AND buildfailure_previous.targetname = buildfailure.targetname + AND buildfailure_previous.language = buildfailure.language + AND buildfailure_previous.outputfile = buildfailure.outputfile + AND buildfailure_previous.outputtype = buildfailure.outputtype + ) + ', [ + 'buildid' => $this->Id, + 'type' => $type, + 'previousbuildid' => $this->GetPreviousBuildId(), + ]); } public function GetConfigures(): PDOStatement|false @@ -1431,8 +1435,7 @@ public function GetLabels($labelarray = []): array|false SELECT l2bf.labelid AS id FROM label2buildfailure AS l2bf LEFT JOIN buildfailure AS bf ON (bf.id=l2bf.buildfailureid) - LEFT JOIN buildfailuredetails AS bfd ON (bfd.id=bf.detailsid) - WHERE bfd.type='0' AND bf.buildid = :buildid)"; + WHERE bf.type='0' AND bf.buildid = :buildid)"; } if (empty($labelarray) || isset($labelarray['build']['warnings'])) { $sql .= @@ -1440,8 +1443,7 @@ public function GetLabels($labelarray = []): array|false SELECT l2bf.labelid AS id FROM label2buildfailure AS l2bf LEFT JOIN buildfailure AS bf ON (bf.id=l2bf.buildfailureid) - LEFT JOIN buildfailuredetails AS bfd ON (bfd.id=bf.detailsid) - WHERE bfd.type='1' AND bf.buildid = :buildid)"; + WHERE bf.type='1' AND bf.buildid = :buildid)"; } if (empty($labelarray) || isset($labelarray['dynamicanalysis']['errors'])) { $sql .= @@ -2038,23 +2040,20 @@ private function GetFailuresForChildren(int $fetchStyle = PDO::FETCH_ASSOC): arr SELECT bf.id, bf.sourcefile, - bfd.language, - bfd.targetname, - bfd.outputfile, - bfd.outputtype, + bf.language, + bf.targetname, + bf.outputfile, + bf.outputtype, bf.workingdirectory, - bfd.stderror, - bfd.stdoutput, - bfd.type, - bfd.exitcondition, + bf.stderror, + bf.stdoutput, + bf.type, + bf.exitcondition, b.subprojectid, sp.name subprojectname FROM buildfailure AS bf - LEFT JOIN buildfailuredetails AS bfd - ON (bfd.id=bf.detailsid) JOIN build b ON bf.buildid = b.id - JOIN subproject AS sp - ON sp.id = b.subprojectid + JOIN subproject AS sp ON sp.id = b.subprojectid WHERE b.parentid = ? '; diff --git a/app/cdash/app/Model/BuildFailure.php b/app/cdash/app/Model/BuildFailure.php index a4ee17e905..a1d43cc89c 100644 --- a/app/cdash/app/Model/BuildFailure.php +++ b/app/cdash/app/Model/BuildFailure.php @@ -19,7 +19,6 @@ use App\Models\Build; use App\Models\RichBuildAlert; -use App\Models\RichBuildAlertDetails; use App\Utils\RepositoryUtils; use CDash\Database; use Illuminate\Support\Facades\DB; @@ -99,15 +98,13 @@ public function Insert(): bool $outputType = $this->OutputType ?? ''; $sourceFile = $this->SourceFile ?? ''; - // Compute the crc32. - $crc32 = crc32($outputFile . $stdOutput . $stdError . $sourceFile); - $db = Database::getInstance(); - // Get details ID if it already exists, otherwise insert a new row. - $failureDetails = RichBuildAlertDetails::firstOrCreate([ - 'crc32' => $crc32, - ], [ + /** @var RichBuildAlert $failure */ + $failure = Build::findOrFail((int) $this->BuildId)->richAlerts()->create([ + 'workingdirectory' => $workingDirectory, + 'sourcefile' => $sourceFile, + 'newstatus' => 0, 'type' => (int) $this->Type, 'stdoutput' => $stdOutput, 'stderror' => $stdError, @@ -118,14 +115,6 @@ public function Insert(): bool 'outputtype' => $outputType, ]); - /** @var RichBuildAlert $failure */ - $failure = Build::findOrFail((int) $this->BuildId)->richAlerts()->create([ - 'detailsid' => $failureDetails->id, - 'workingdirectory' => $workingDirectory, - 'sourcefile' => $sourceFile, - 'newstatus' => 0, - ]); - // Insert the arguments $argumentids = []; @@ -187,17 +176,15 @@ public function GetFailuresForBuild(int $fetchStyle = PDO::FETCH_ASSOC): array|f bf.workingdirectory, bf.sourcefile, bf.newstatus, - bfd.stdoutput, - bfd.stderror, - bfd.type, - bfd.exitcondition, - bfd.language, - bfd.targetname, - bfd.outputfile, - bfd.outputtype - FROM buildfailuredetails AS bfd - LEFT JOIN buildfailure AS bf - ON (bf.detailsid = bfd.id) + bf.stdoutput, + bf.stderror, + bf.type, + bf.exitcondition, + bf.language, + bf.targetname, + bf.outputfile, + bf.outputtype + FROM buildfailure AS bf WHERE bf.buildid=? ORDER BY bf.id '; diff --git a/app/cdash/tests/test_buildfailuredetails.php b/app/cdash/tests/test_buildfailuredetails.php index c1ead79ce0..106676d7fa 100644 --- a/app/cdash/tests/test_buildfailuredetails.php +++ b/app/cdash/tests/test_buildfailuredetails.php @@ -45,8 +45,7 @@ public function testBuildFailureDetails() // Verify 4 buildfailures, 2 builds, and 2 details. $count_query = " SELECT COUNT(DISTINCT bf.id) AS numfails, - COUNT(DISTINCT bf.buildid) AS numbuilds, - COUNT(DISTINCT bf.detailsid) AS numdetails + COUNT(DISTINCT bf.buildid) AS numbuilds FROM buildfailure AS bf LEFT JOIN build AS b ON (b.id=bf.buildid) WHERE b.name='test_buildfailure'"; @@ -61,11 +60,6 @@ public function testBuildFailureDetails() 'Expected 2 builds, found ' . $count_results->numbuilds); return 1; } - if ((int) $count_results->numdetails !== 2) { - $this->fail( - 'Expected 2 buildfailuredetails, found ' . $count_results->numdetails); - return 1; - } // Delete one of the builds. DatabaseCleanupUtils::removeBuild($buildids[0]); @@ -82,11 +76,6 @@ public function testBuildFailureDetails() 'Expected 1 build, found ' . $count_results->numbuilds); return 1; } - if ((int) $count_results->numdetails !== 2) { - $this->fail( - 'Expected 2 buildfailuredetails, found ' . $count_results->numdetails); - return 1; - } // Delete the other build. DatabaseCleanupUtils::removeBuild($buildids[1]); @@ -103,11 +92,6 @@ public function testBuildFailureDetails() 'Expected 0 builds, found ' . $count_results->numbuilds); return 1; } - if ((int) $count_results->numdetails !== 0) { - $this->fail( - 'Expected 0 buildfailuredetails, found ' . $count_results->numdetails); - return 1; - } $this->pass('Test passed'); return 0; diff --git a/app/cdash/tests/test_buildmodel.php b/app/cdash/tests/test_buildmodel.php index db982609f1..500c88d3c2 100644 --- a/app/cdash/tests/test_buildmodel.php +++ b/app/cdash/tests/test_buildmodel.php @@ -247,17 +247,17 @@ public function testBuildModelGetsResolvedBuildFailures(): void { // Make sure the first build returns no resolved build failures since it can't have any $build = $this->getBuildModel(0); - $this->assertTrue($build->GetResolvedBuildFailures(0)->fetchAll() === []); + $this->assertTrue($build->GetResolvedBuildFailures(0) === []); // The second build resolves the errored failure, but not the warning failure $build = $this->getBuildModel(1); - $this->assertTrue(count($build->GetResolvedBuildFailures(0)->fetchAll()) === 1); - $this->assertTrue($build->GetResolvedBuildFailures(1)->fetchAll() === []); + $this->assertTrue(count($build->GetResolvedBuildFailures(0)) === 1); + $this->assertTrue($build->GetResolvedBuildFailures(1) === []); // The third build has a resolved failure of type warning $build = $this->getBuildModel(2); - $this->assertTrue(count($build->GetResolvedBuildFailures(0)->fetchAll()) === 0); - $this->assertTrue(count($build->GetResolvedBuildFailures(1)->fetchAll()) === 1); + $this->assertTrue(count($build->GetResolvedBuildFailures(0)) === 0); + $this->assertTrue(count($build->GetResolvedBuildFailures(1)) === 1); } public function testBuildModelGetErrors(): void diff --git a/app/cdash/tests/test_removebuilds.php b/app/cdash/tests/test_removebuilds.php index 82c55a0b2e..2134e0f587 100644 --- a/app/cdash/tests/test_removebuilds.php +++ b/app/cdash/tests/test_removebuilds.php @@ -367,17 +367,6 @@ public function testBuildRemovalWorksAsExpected(): void // Insert some unused records to make sure they get properly pruned by db:clean // without impacting the data created above. $crc32 = crc32(''); - $buildfailuredetails_id = DB::table('buildfailuredetails')->insertGetId([ - 'type' => 0, - 'stdoutput' => '', - 'stderror' => '', - 'exitcondition' => 'normal', - 'language' => 'PHP', - 'targetname' => 'test_removebuilds', - 'outputfile' => 'test_removebuilds', - 'outputtype' => 'test', - 'crc32' => $crc32, - ]); $configure_id = DB::table('configure')->insertGetId([ 'command' => 'test_removebuilds', 'log' => 'created by test_removebuilds', @@ -414,7 +403,6 @@ public function testBuildRemovalWorksAsExpected(): void // Verify that db:clean works as expected. Artisan::call('db:clean'); $extra_msg = 'after db:clean'; - $this->verify('buildfailuredetails', 'id', '=', $buildfailuredetails_id, 0, $extra_msg); $this->verify('configure', 'id', '=', $configure_id, 0, $extra_msg); $this->verify('coveragefile', 'id', '=', $coveragefile_id, 0, $extra_msg); $this->verify('image', 'id', '=', $image_id, 0, $extra_msg); @@ -437,10 +425,9 @@ public function testBuildRemovalWorksAsExpected(): void $this->verify('summaryemail', 'buildid', '=', $build->Id, 1); $this->verify('testdiff', 'buildid', '=', $build->Id, 1); - [$buildfailureid, $detailsid] = - $this->verify_get_columns('buildfailure', ['id', 'detailsid'], 'buildid', '=', $build->Id, 1); + [$buildfailureid] = + $this->verify_get_columns('buildfailure', ['id'], 'buildid', '=', $build->Id, 1); $this->verify('buildfailure2argument', 'buildfailureid', '=', $buildfailureid, 1); - $this->verify('buildfailuredetails', 'id', '=', $detailsid, 1); $configureid = $this->verify_get_rows('build2configure', 'configureid', 'buildid', '=', $build->Id, 1); @@ -497,7 +484,6 @@ public function testBuildRemovalWorksAsExpected(): void $this->verify('builderrordiff', 'buildid', '=', $build->Id, 0, $extra_msg); $this->verify('buildfailure', 'buildid', '=', $build->Id, 0, $extra_msg); $this->verify('buildfailure2argument', 'buildfailureid', '=', $buildfailureid, 0, $extra_msg); - $this->verify('buildfailuredetails', 'id', '=', $detailsid, 1, $extra_msg); $this->verify('buildtesttime', 'buildid', '=', $build->Id, 0, $extra_msg); $this->verify('buildupdate', 'id', '=', $updateid, 1, $extra_msg); $this->verify('configure', 'id', '=', $configureid, 1, $extra_msg); @@ -538,7 +524,6 @@ public function testBuildRemovalWorksAsExpected(): void $this->verify('builderror', 'buildid', '=', $existing_build->Id, 0, $extra_msg); $this->verify('builderrordiff', 'buildid', '=', $existing_build->Id, 0, $extra_msg); $this->verify('buildfailure', 'buildid', '=', $existing_build->Id, 0, $extra_msg); - $this->verify('buildfailuredetails', 'id', '=', $detailsid, 0, $extra_msg); $this->verify('buildtesttime', 'buildid', '=', $existing_build->Id, 0, $extra_msg); $this->verify('buildupdate', 'id', '=', $updateid, 0, $extra_msg); $this->verify('configure', 'id', '=', $configureid, 0, $extra_msg); diff --git a/database/migrations/2026_01_27_131726_move_buildfailuredetails_to_buildfailure_table.php b/database/migrations/2026_01_27_131726_move_buildfailuredetails_to_buildfailure_table.php new file mode 100644 index 0000000000..d1ef56c496 --- /dev/null +++ b/database/migrations/2026_01_27_131726_move_buildfailuredetails_to_buildfailure_table.php @@ -0,0 +1,57 @@ +