Merge pull request #228 from copenhagentruckwash/fix-partial-release-tests-bypassing-promotion-gate

Require app-scoped release gates for bundle promotion
This commit is contained in:
Jeppe B
2026-06-01 23:23:34 +02:00
committed by GitHub
2 changed files with 13 additions and 4 deletions
@@ -1021,6 +1021,7 @@ class release_manager
'channel_slug' => $channelSlug,
'route_slug' => $routeSlug,
'app' => $app,
'apps' => $this->releaseTestAppsFromInput($input),
'repository' => $repository,
'branch' => $branch,
'auto_sync' => $this->toBool($input['auto_sync'] ?? false),
@@ -4802,22 +4803,22 @@ class release_manager
throw new RuntimeException('Beta release channel uses production services and does not promote separate release bundles.');
}
$this->assertBetaProductionDataPolicy($channel, $serviceSet);
$frontendVersionId = $this->nullablePositiveInt($bundle['frontend_version_id'] ?? null);
$apiVersionId = $this->nullablePositiveInt($bundle['api_version_id'] ?? null);
$this->assertReleaseGatePassedForPromotion(
$channelId,
(string)($bundle['frontend_commit_sha'] ?? ''),
null,
'frontend'
);
if (trim((string)($bundle['api_commit_sha'] ?? '')) !== '') {
if ($apiVersionId !== null) {
$this->assertReleaseGatePassedForPromotion(
$channelId,
(string)$bundle['api_commit_sha'],
(string)($bundle['api_commit_sha'] ?? ''),
null,
'api'
);
}
$frontendVersionId = $this->nullablePositiveInt($bundle['frontend_version_id'] ?? null);
$apiVersionId = $this->nullablePositiveInt($bundle['api_version_id'] ?? null);
$deploymentId = $this->nullablePositiveInt($bundle['api_deployment_id'] ?? null)
?? $this->nullablePositiveInt($bundle['frontend_deployment_id'] ?? null);
@@ -83,6 +83,7 @@ it('normalizes app-specific release gate auto-sync metadata', function (): void
'channel_slug' => 'stable',
'route_slug' => 'master',
'app' => 'api',
'apps' => ['api'],
'repository' => 'copenhagentruckwash/api',
'branch' => 'master',
'expected_commit' => 'd52ceb85138740c45f20cda9b7ed9b7a21f0d4e8',
@@ -90,6 +91,11 @@ it('normalizes app-specific release gate auto-sync metadata', function (): void
'auto_sync' => true,
]);
$fullStackGate = $normalizeGate->invoke($manager, [
'channel_slug' => 'stable',
], ['slug' => 'stable']);
expect($fullStackGate['apps'])->toBe(['frontend', 'api']);
expect($appMatches->invoke($manager, ['app' => 'api'], 'api'))->toBeTrue();
expect($appMatches->invoke($manager, ['apps' => ['frontend', 'api']], 'api'))->toBeTrue();
expect($appMatches->invoke($manager, [], 'frontend'))->toBeTrue();
@@ -899,6 +905,7 @@ it('defines release manager schema, routes, permissions, and system-status integ
expect($manager)->toContain('createBundle');
expect($manager)->toContain('deployBundle');
expect($manager)->toContain('promoteBundle');
expect($manager)->toContain('if ($apiVersionId !== null)');
expect($manager)->toContain('setChannelBundle');
expect($manager)->toContain('searchAssignmentSubjects');
expect($manager)->toContain('publicAssignmentSubjectSuggestion');
@@ -975,6 +982,7 @@ it('defines release manager schema, routes, permissions, and system-status integ
expect($manager)->toContain('channelSlugForRoute');
expect($manager)->toContain('syncChannel');
expect($manager)->toContain('runReleaseTest');
expect($manager)->toContain("'apps' => \$this->releaseTestAppsFromInput(\$input)");
expect($manager)->toContain('releaseTestAppsFromInput');
expect($manager)->toContain('release_operation_runs');
expect($manager)->toContain('active_channel_app_key');