mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-22 00:05:37 +08:00
Add frankenphp test label
This commit is contained in:
4
.github/workflows/tests.yml
vendored
4
.github/workflows/tests.yml
vendored
@@ -227,7 +227,7 @@ jobs:
|
|||||||
echo "matrix=$(echo "$FINAL" | jq -c '{"combo": .}')" >> "$GITHUB_OUTPUT"
|
echo "matrix=$(echo "$FINAL" | jq -c '{"combo": .}')" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
ext-test:
|
ext-test:
|
||||||
name: "Ext test: ${{ matrix.combo.extension }} (PHP ${{ matrix.combo.php-version }} · ${{ matrix.combo.os }}-${{ matrix.combo.arch }})"
|
name: "Ext test: ${{ matrix.combo.extension }} [${{ matrix.combo.sapi }}] (PHP ${{ matrix.combo.php-version }} - ${{ matrix.combo.os }}-${{ matrix.combo.arch }})"
|
||||||
needs: gen-matrix
|
needs: gen-matrix
|
||||||
runs-on: ${{ matrix.combo.runner }}
|
runs-on: ${{ matrix.combo.runner }}
|
||||||
timeout-minutes: 120
|
timeout-minutes: 120
|
||||||
@@ -266,5 +266,5 @@ jobs:
|
|||||||
if: always() && hashFiles('log/**') != ''
|
if: always() && hashFiles('log/**') != ''
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: logs-${{ matrix.combo.os }}-${{ matrix.combo.arch }}-${{ matrix.combo.extension }}-php${{ matrix.combo.php-version }}
|
name: logs-${{ matrix.combo.os }}-${{ matrix.combo.arch }}-${{ matrix.combo.sapi }}-${{ matrix.combo.extension }}-php${{ matrix.combo.php-version }}
|
||||||
path: log
|
path: log
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ class GenExtTestMatrixCommand extends BaseCommand
|
|||||||
{
|
{
|
||||||
private const string BUILD_TARGETS = '--build-cli --build-cgi --build-micro --with-suggests -vvv';
|
private const string BUILD_TARGETS = '--build-cli --build-cgi --build-micro --with-suggests -vvv';
|
||||||
|
|
||||||
|
private const string FRANKENPHP_BUILD_TARGETS = '--build-cli --build-frankenphp --enable-zts --with-suggests -vvv';
|
||||||
|
|
||||||
|
private const array SUPPORTED_SAPIS = [
|
||||||
|
'frankenphp',
|
||||||
|
];
|
||||||
|
|
||||||
private const array OS_RUNNERS = [
|
private const array OS_RUNNERS = [
|
||||||
'linux' => ['arch' => 'x86_64', 'runner' => 'ubuntu-latest', 'os_key' => 'Linux'],
|
'linux' => ['arch' => 'x86_64', 'runner' => 'ubuntu-latest', 'os_key' => 'Linux'],
|
||||||
'windows' => ['arch' => 'x86_64', 'runner' => 'windows-2025', 'os_key' => 'Windows'],
|
'windows' => ['arch' => 'x86_64', 'runner' => 'windows-2025', 'os_key' => 'Windows'],
|
||||||
@@ -84,6 +90,7 @@ class GenExtTestMatrixCommand extends BaseCommand
|
|||||||
$this->addOption('for-extensions', null, InputOption::VALUE_OPTIONAL, 'Filter by extension display names, comma-separated', '')
|
$this->addOption('for-extensions', null, InputOption::VALUE_OPTIONAL, 'Filter by extension display names, comma-separated', '')
|
||||||
->addOption('for-libs', null, InputOption::VALUE_OPTIONAL, 'Filter by lib names (depends+suggests), comma-separated', '')
|
->addOption('for-libs', null, InputOption::VALUE_OPTIONAL, 'Filter by lib names (depends+suggests), comma-separated', '')
|
||||||
->addOption('os', null, InputOption::VALUE_OPTIONAL, 'Filter by OS (Linux/Darwin/Windows), comma-separated', '')
|
->addOption('os', null, InputOption::VALUE_OPTIONAL, 'Filter by OS (Linux/Darwin/Windows), comma-separated', '')
|
||||||
|
->addOption('sapi', null, InputOption::VALUE_OPTIONAL, 'Add extra SAPI build tests, comma-separated (supported: frankenphp)', '')
|
||||||
->addOption('tier2', null, InputOption::VALUE_NONE, 'Use Tier 2 runners (Linux aarch64 + macOS x86_64, no Windows)');
|
->addOption('tier2', null, InputOption::VALUE_NONE, 'Use Tier 2 runners (Linux aarch64 + macOS x86_64, no Windows)');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,8 +105,15 @@ class GenExtTestMatrixCommand extends BaseCommand
|
|||||||
$filter_extensions = $parse_option('for-extensions');
|
$filter_extensions = $parse_option('for-extensions');
|
||||||
$filter_libs = $parse_option('for-libs');
|
$filter_libs = $parse_option('for-libs');
|
||||||
$filter_os_keys = $parse_option('os');
|
$filter_os_keys = $parse_option('os');
|
||||||
|
$filter_sapis = array_unique($parse_option('sapi'));
|
||||||
$tier2 = (bool) $this->input->getOption('tier2');
|
$tier2 = (bool) $this->input->getOption('tier2');
|
||||||
|
|
||||||
|
$unknown_sapis = array_values(array_diff($filter_sapis, self::SUPPORTED_SAPIS));
|
||||||
|
if (!empty($unknown_sapis)) {
|
||||||
|
$this->output->writeln('<error>Unsupported SAPI(s): ' . implode(', ', $unknown_sapis) . '</error>');
|
||||||
|
return static::USER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
$base_runners = $tier2 ? self::OS_RUNNERS_TIER2 : self::OS_RUNNERS;
|
$base_runners = $tier2 ? self::OS_RUNNERS_TIER2 : self::OS_RUNNERS;
|
||||||
|
|
||||||
$all = PackageConfig::getAll();
|
$all = PackageConfig::getAll();
|
||||||
@@ -126,6 +140,67 @@ class GenExtTestMatrixCommand extends BaseCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[$entries, $all_ext_lib_deps] = $this->buildEntriesForRunners(
|
||||||
|
$base_runners,
|
||||||
|
$filter_os_keys,
|
||||||
|
$all_regular,
|
||||||
|
$all_virtual,
|
||||||
|
$all_libraries,
|
||||||
|
self::BUILD_TARGETS,
|
||||||
|
'default',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (in_array('frankenphp', $filter_sapis, true)) {
|
||||||
|
[$frankenphp_entries, $frankenphp_ext_lib_deps] = $this->buildEntriesForRunners(
|
||||||
|
self::OS_RUNNERS,
|
||||||
|
[],
|
||||||
|
$all_regular,
|
||||||
|
$all_virtual,
|
||||||
|
$all_libraries,
|
||||||
|
self::FRANKENPHP_BUILD_TARGETS,
|
||||||
|
'frankenphp',
|
||||||
|
);
|
||||||
|
$entries = array_merge($entries, $frankenphp_entries);
|
||||||
|
$all_ext_lib_deps = array_replace_recursive($all_ext_lib_deps, $frankenphp_ext_lib_deps);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($filter_extensions) || !empty($filter_libs)) {
|
||||||
|
$entries = array_values(array_filter($entries, function (array $entry) use ($filter_extensions, $filter_libs, $all_ext_lib_deps): bool {
|
||||||
|
$names = explode(',', $entry['extension']);
|
||||||
|
|
||||||
|
if (!empty($filter_extensions) && count(array_intersect($names, $filter_extensions)) > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($filter_libs)) {
|
||||||
|
$lib_deps = $all_ext_lib_deps[$entry['os']] ?? [];
|
||||||
|
foreach ($names as $name) {
|
||||||
|
if (count(array_intersect($lib_deps[$name] ?? [], $filter_libs)) > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->output->write(json_encode($entries, JSON_UNESCAPED_SLASHES));
|
||||||
|
return static::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{array<int, array<string, string>>, array<string, array<string, string[]>>}
|
||||||
|
*/
|
||||||
|
private function buildEntriesForRunners(
|
||||||
|
array $base_runners,
|
||||||
|
array $filter_os_keys,
|
||||||
|
array $all_regular,
|
||||||
|
array $all_virtual,
|
||||||
|
array $all_libraries,
|
||||||
|
string $build_targets,
|
||||||
|
string $sapi,
|
||||||
|
): array {
|
||||||
$os_runners = empty($filter_os_keys)
|
$os_runners = empty($filter_os_keys)
|
||||||
? $base_runners
|
? $base_runners
|
||||||
: array_filter($base_runners, fn ($info) => in_array($info['os_key'], $filter_os_keys, true));
|
: array_filter($base_runners, fn ($info) => in_array($info['os_key'], $filter_os_keys, true));
|
||||||
@@ -237,40 +312,18 @@ class GenExtTestMatrixCommand extends BaseCommand
|
|||||||
|
|
||||||
sort($groups);
|
sort($groups);
|
||||||
foreach ($groups as $group) {
|
foreach ($groups as $group) {
|
||||||
$extra = $this->extraBuildFlags($group);
|
|
||||||
$entries[] = [
|
$entries[] = [
|
||||||
'runner' => $os_info['runner'],
|
'runner' => $os_info['runner'],
|
||||||
'os' => $os,
|
'os' => $os,
|
||||||
'arch' => $os_info['arch'],
|
'arch' => $os_info['arch'],
|
||||||
|
'sapi' => $sapi,
|
||||||
'extension' => $group,
|
'extension' => $group,
|
||||||
'build-args' => './bin/spc build "' . $group . '" ' . self::BUILD_TARGETS . ($extra !== '' ? ' ' . $extra : ''),
|
'build-args' => './bin/spc build "' . $group . '" ' . $this->buildTargetsWithExtraFlags($build_targets, $group),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($filter_extensions) || !empty($filter_libs)) {
|
return [$entries, $all_ext_lib_deps];
|
||||||
$entries = array_values(array_filter($entries, function (array $entry) use ($filter_extensions, $filter_libs, $all_ext_lib_deps): bool {
|
|
||||||
$names = explode(',', $entry['extension']);
|
|
||||||
|
|
||||||
if (!empty($filter_extensions) && count(array_intersect($names, $filter_extensions)) > 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($filter_libs)) {
|
|
||||||
$lib_deps = $all_ext_lib_deps[$entry['os']] ?? [];
|
|
||||||
foreach ($names as $name) {
|
|
||||||
if (count(array_intersect($lib_deps[$name] ?? [], $filter_libs)) > 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->output->write(json_encode($entries, JSON_UNESCAPED_SLASHES));
|
|
||||||
return static::SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -397,6 +450,18 @@ class GenExtTestMatrixCommand extends BaseCommand
|
|||||||
return implode(' ', $flags);
|
return implode(' ', $flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildTargetsWithExtraFlags(string $build_targets, string $group): string
|
||||||
|
{
|
||||||
|
$flags = explode(' ', $build_targets);
|
||||||
|
foreach (explode(' ', $this->extraBuildFlags($group)) as $extra) {
|
||||||
|
if ($extra === '' || in_array($extra, $flags, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$flags[] = $extra;
|
||||||
|
}
|
||||||
|
return implode(' ', $flags);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve the value of a platform-specific array field, applying the suffix fallback chain.
|
* Resolve the value of a platform-specific array field, applying the suffix fallback chain.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ class TestBotCommand extends BaseCommand
|
|||||||
|
|
||||||
private const string TIER2_LABEL = 'test/tier2';
|
private const string TIER2_LABEL = 'test/tier2';
|
||||||
|
|
||||||
|
private const array SAPI_LABELS = [
|
||||||
|
'sapi/frankenphp' => 'frankenphp',
|
||||||
|
];
|
||||||
|
|
||||||
/** PHP version labels → version string (8.5 is always included as default) */
|
/** PHP version labels → version string (8.5 is always included as default) */
|
||||||
private const array PHP_VERSION_LABELS = [
|
private const array PHP_VERSION_LABELS = [
|
||||||
'test/php-83' => '8.3',
|
'test/php-83' => '8.3',
|
||||||
@@ -93,6 +97,12 @@ class TestBotCommand extends BaseCommand
|
|||||||
}
|
}
|
||||||
$tier2 = in_array(self::TIER2_LABEL, $label_names, true);
|
$tier2 = in_array(self::TIER2_LABEL, $label_names, true);
|
||||||
$need_test = in_array('need-test', $label_names, true);
|
$need_test = in_array('need-test', $label_names, true);
|
||||||
|
$sapis = [];
|
||||||
|
foreach (self::SAPI_LABELS as $label => $sapi) {
|
||||||
|
if (in_array($label, $label_names, true)) {
|
||||||
|
$sapis[] = $sapi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Resolve PHP versions (default always included)
|
// Resolve PHP versions (default always included)
|
||||||
$php_versions = [self::DEFAULT_PHP_VERSION];
|
$php_versions = [self::DEFAULT_PHP_VERSION];
|
||||||
@@ -119,6 +129,9 @@ class TestBotCommand extends BaseCommand
|
|||||||
if (!empty($os_keys)) {
|
if (!empty($os_keys)) {
|
||||||
$flag_parts[] = '--os=' . implode(',', $os_keys);
|
$flag_parts[] = '--os=' . implode(',', $os_keys);
|
||||||
}
|
}
|
||||||
|
if (!empty($sapis)) {
|
||||||
|
$flag_parts[] = '--sapi=' . implode(',', $sapis);
|
||||||
|
}
|
||||||
$gen_matrix_args = implode(' ', $flag_parts);
|
$gen_matrix_args = implode(' ', $flag_parts);
|
||||||
|
|
||||||
if ($tier2) {
|
if ($tier2) {
|
||||||
@@ -128,7 +141,7 @@ class TestBotCommand extends BaseCommand
|
|||||||
fn ($k) => $k !== 'Windows'
|
fn ($k) => $k !== 'Windows'
|
||||||
));
|
));
|
||||||
if (!empty($tier2_os)) {
|
if (!empty($tier2_os)) {
|
||||||
$tier2_parts = array_values(array_filter($flag_parts, fn ($f) => !str_starts_with($f, '--os=')));
|
$tier2_parts = array_values(array_filter($flag_parts, fn ($f) => !str_starts_with($f, '--os=') && !str_starts_with($f, '--sapi=')));
|
||||||
$tier2_parts[] = '--os=' . implode(',', $tier2_os);
|
$tier2_parts[] = '--os=' . implode(',', $tier2_os);
|
||||||
$tier2_parts[] = '--tier2';
|
$tier2_parts[] = '--tier2';
|
||||||
$gen_matrix_args_tier2 = implode(' ', $tier2_parts);
|
$gen_matrix_args_tier2 = implode(' ', $tier2_parts);
|
||||||
@@ -143,6 +156,7 @@ class TestBotCommand extends BaseCommand
|
|||||||
$label_names,
|
$label_names,
|
||||||
$os_keys,
|
$os_keys,
|
||||||
$tier2,
|
$tier2,
|
||||||
|
$sapis,
|
||||||
$php_versions,
|
$php_versions,
|
||||||
$need_test,
|
$need_test,
|
||||||
);
|
);
|
||||||
@@ -156,6 +170,7 @@ class TestBotCommand extends BaseCommand
|
|||||||
'gen_matrix_args_tier2' => $gen_matrix_args_tier2,
|
'gen_matrix_args_tier2' => $gen_matrix_args_tier2,
|
||||||
'php_versions' => $php_versions,
|
'php_versions' => $php_versions,
|
||||||
'tier2' => $tier2,
|
'tier2' => $tier2,
|
||||||
|
'sapis' => $sapis,
|
||||||
'comment_body' => $comment_body,
|
'comment_body' => $comment_body,
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -239,6 +254,7 @@ class TestBotCommand extends BaseCommand
|
|||||||
array $label_names,
|
array $label_names,
|
||||||
array $os_keys,
|
array $os_keys,
|
||||||
bool $tier2,
|
bool $tier2,
|
||||||
|
array $sapis,
|
||||||
array $php_versions,
|
array $php_versions,
|
||||||
bool $need_test,
|
bool $need_test,
|
||||||
): string {
|
): string {
|
||||||
@@ -258,6 +274,7 @@ class TestBotCommand extends BaseCommand
|
|||||||
'`test/linux` `test/windows` `test/macos` (platform)',
|
'`test/linux` `test/windows` `test/macos` (platform)',
|
||||||
'`test/tier2` (extra arch)',
|
'`test/tier2` (extra arch)',
|
||||||
'`test/php-83` `test/php-84` (PHP version)',
|
'`test/php-83` `test/php-84` (PHP version)',
|
||||||
|
'`sapi/frankenphp` (extra FrankenPHP SAPI build)',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Case 1: need-test absent → invite the author to add it
|
// Case 1: need-test absent → invite the author to add it
|
||||||
@@ -303,7 +320,8 @@ class TestBotCommand extends BaseCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
$php_str = implode(', ', array_map(fn ($v) => "PHP {$v}", $php_versions)) . ' NTS';
|
$php_str = implode(', ', array_map(fn ($v) => "PHP {$v}", $php_versions)) . ' NTS';
|
||||||
$active_test_labels = array_values(array_filter($label_names, fn ($l) => str_starts_with($l, 'test/')));
|
$sapi_str = !empty($sapis) ? ' + SAPI: ' . implode(', ', $sapis) . ' (Tier1 Linux/macOS/Windows)' : '';
|
||||||
|
$active_test_labels = array_values(array_filter($label_names, fn ($l) => str_starts_with($l, 'test/') || str_starts_with($l, 'sapi/')));
|
||||||
$labels_str = !empty($active_test_labels) ? '`' . implode('`, `', $active_test_labels) . '`' : '_none_';
|
$labels_str = !empty($active_test_labels) ? '`' . implode('`, `', $active_test_labels) . '`' : '_none_';
|
||||||
|
|
||||||
return implode("\n", [
|
return implode("\n", [
|
||||||
@@ -313,7 +331,7 @@ class TestBotCommand extends BaseCommand
|
|||||||
$detected,
|
$detected,
|
||||||
'**Active labels**: ' . $labels_str,
|
'**Active labels**: ' . $labels_str,
|
||||||
'**Available labels**: ' . $available_labels,
|
'**Available labels**: ' . $available_labels,
|
||||||
'**Config**: ' . implode(' + ', $platform_parts) . ' | ' . $php_str,
|
'**Config**: ' . implode(' + ', $platform_parts) . ' | ' . $php_str . $sapi_str,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user