Skip to content

Commit d710f8b

Browse files
committed
fix: run wp-cli wrapper directly in test installer
1 parent b35d81b commit d710f8b

3 files changed

Lines changed: 146 additions & 2 deletions

File tree

.beads/issues.jsonl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,11 @@
1+
{"id":"srbtranslatin-3qs","title":"Run public parity verification gates","description":"Run the project quality gates and parity regression suite after implementation. Cover existing parity tests plus new media/files, permalink, selector widget, stl_selector alias, and multilingual resolver tests; run PHPStan if it is part of the project gate.","acceptance_criteria":"vendor/bin/phpunit passes; PHPStan is run if configured; failures are fixed or documented in follow-up beads; manual smoke-test checklist is captured in handoff for frontend Latin output, AJAX JSON/HTML, search, shortcodes, menus, widgets, media upload/URL switching, permalinks, and multilingual contexts.","status":"closed","priority":1,"issue_type":"task","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-06-28T09:25:00Z","created_by":"Sibin Grasic","updated_at":"2026-06-28T10:36:38Z","started_at":"2026-06-28T09:39:30Z","closed_at":"2026-06-28T10:36:38Z","close_reason":"Verified with vendor/bin/phpunit and vendor/bin/phpstan analyse --memory-limit=512M. Manual smoke-test checklist remains documented in handoff because browser/WP manual flows were not run in this terminal session.","dependencies":[{"issue_id":"srbtranslatin-3qs","depends_on_id":"srbtranslatin-68s","type":"blocks","created_at":"2026-06-28T11:25:19Z","created_by":"Sibin Grasic","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
2+
{"id":"srbtranslatin-d40","title":"Add multilingual locale resolvers","description":"Expand public multilingual compatibility beyond WPML by adding active-language locale resolution for Polylang, TranslatePress, and qTranslateX. Keep existing WPML support and avoid adding non-WPML switcher mutation unless tests or public behavior require it.","acceptance_criteria":"Script decisions can resolve active locale from WPML, Polylang, TranslatePress, and qTranslateX contexts; get_locale remains the fallback; focused tests cover each resolver and fallback behavior.","status":"closed","priority":1,"issue_type":"feature","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-06-28T09:24:49Z","created_by":"Sibin Grasic","updated_at":"2026-06-28T09:37:39Z","started_at":"2026-06-28T09:35:07Z","closed_at":"2026-06-28T09:37:39Z","close_reason":"Implemented runtime parity with focused unit coverage for media/files, permalinks, selector compatibility, and multilingual locale resolvers.","dependency_count":0,"dependent_count":1,"comment_count":0}
3+
{"id":"srbtranslatin-7n2","title":"Restore legacy selector compatibility","description":"Restore public selector compatibility by registering the legacy Selector_Widget from the active src boot path and adding a documented stl_selector() compatibility shim that delegates to stl_script_selector().","acceptance_criteria":"Selector_Widget is registered through the active plugin bootstrap; stl_selector args and echo parameters are accepted as a compatibility alias for stl_script_selector; widget registration and alias output behavior have PHPUnit coverage.","status":"closed","priority":1,"issue_type":"feature","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-06-28T09:24:44Z","created_by":"Sibin Grasic","updated_at":"2026-06-28T09:37:39Z","started_at":"2026-06-28T09:32:41Z","closed_at":"2026-06-28T09:37:39Z","close_reason":"Implemented runtime parity with focused unit coverage for media/files, permalinks, selector compatibility, and multilingual locale resolvers.","dependency_count":0,"dependent_count":1,"comment_count":0}
4+
{"id":"srbtranslatin-czn","title":"Implement permalink transliteration parity","description":"Implement the advanced.fix_permalinks public claim with a gated sanitize_title filter. Preserve locale-based disabling where WordPress already handles Serbian or Bosnian slugs automatically so the plugin does not fight core behavior.","acceptance_criteria":"advanced.fix_permalinks enables Cyrillic-to-Latin slug sanitization through sanitize_title; the behavior is disabled when locale/core support should own Serbian or Bosnian slug handling; PHPUnit coverage documents enabled and disabled cases.","status":"closed","priority":1,"issue_type":"feature","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-06-28T09:24:34Z","created_by":"Sibin Grasic","updated_at":"2026-06-28T09:37:38Z","started_at":"2026-06-28T09:31:12Z","closed_at":"2026-06-28T09:37:38Z","close_reason":"Implemented runtime parity with focused unit coverage for media/files, permalinks, selector compatibility, and multilingual locale resolvers.","dependency_count":0,"dependent_count":1,"comment_count":0}
5+
{"id":"srbtranslatin-ei8","title":"Implement media and file parity runtime","description":"Add runtime support for public media/file claims: transliterate uploaded filenames when media.transliterate_uploads is enabled, rewrite script-specific media/file URLs when media.separate_uploads is enabled with configured separator plus __cir/__lat compatibility, respect media.transliteration_method for whole-page versus content-only rewriting, and only expose media settings once backed by runtime behavior.","acceptance_criteria":"Uploaded filenames are transliterated behind the existing media.transliterate_uploads setting; media/file URLs, srcset, and href values switch between scripts when media.separate_uploads is enabled; legacy __cir/__lat filenames remain compatible; media.transliteration_method gates whole-page versus content-only rewriting; focused PHPUnit coverage exists.","status":"closed","priority":1,"issue_type":"feature","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-06-28T09:24:27Z","created_by":"Sibin Grasic","updated_at":"2026-06-28T09:37:38Z","started_at":"2026-06-28T09:26:24Z","closed_at":"2026-06-28T09:37:38Z","close_reason":"Implemented runtime parity with focused unit coverage for media/files, permalinks, selector compatibility, and multilingual locale resolvers.","dependency_count":0,"dependent_count":1,"comment_count":0}
6+
{"id":"srbtranslatin-10g","title":"Fix WordPress test harness installation for full PHPUnit","description":"The full PHPUnit suite requires .cache/wp-tests, but composer test:install failed while deriving the WordPress core version from the local WP-CLI proxy, leaving the wordpress-develop download path empty. Fix the test setup so vendor/bin/phpunit can bootstrap the WordPress test suite locally.","status":"closed","priority":2,"issue_type":"bug","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-06-28T11:02:30Z","created_by":"Sibin Grasic","updated_at":"2026-06-28T11:21:02Z","started_at":"2026-06-28T11:17:08Z","closed_at":"2026-06-28T11:21:02Z","close_reason":"Fixed WP-CLI wrapper execution in install-wp-tests.sh and added regression coverage for Composer proxy wrappers.","dependency_count":0,"dependent_count":0,"comment_count":0}
7+
{"id":"srbtranslatin-ooq","title":"Restore active media transliteration runtime","description":"Implement media settings parity, upload filename transliteration, and Latin-page image URL rewriting in the active src runtime without generating duplicate media files.","status":"closed","priority":2,"issue_type":"feature","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-06-28T10:53:41Z","created_by":"Sibin Grasic","updated_at":"2026-06-28T11:02:35Z","started_at":"2026-06-28T10:53:47Z","closed_at":"2026-06-28T11:02:35Z","close_reason":"Implemented active media settings, upload filename transliteration, Latin image URL rewriting, handler/module wiring, and unit coverage.","dependency_count":0,"dependent_count":0,"comment_count":0}
8+
{"id":"srbtranslatin-68s","title":"Align public docs with implemented parity","description":"Restore or update WordPress.org and readme-facing documentation after runtime parity work is complete so every listed public feature is implemented and tested. Remove or correct stale wording only after feature behavior exists.","acceptance_criteria":"Readme/public docs accurately describe implemented media, permalink, selector, multilingual, cache, and SEO behavior; no public claim remains unsupported by runtime code or tests.","status":"closed","priority":2,"issue_type":"task","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-06-28T09:24:54Z","created_by":"Sibin Grasic","updated_at":"2026-06-28T09:39:24Z","started_at":"2026-06-28T09:37:50Z","closed_at":"2026-06-28T09:39:24Z","close_reason":"Updated WordPress.org readme, GitHub README, and parity notes to reflect implemented media, permalink, selector, and multilingual behavior.","dependencies":[{"issue_id":"srbtranslatin-68s","depends_on_id":"srbtranslatin-7n2","type":"blocks","created_at":"2026-06-28T11:25:12Z","created_by":"Sibin Grasic","metadata":"{}"},{"issue_id":"srbtranslatin-68s","depends_on_id":"srbtranslatin-czn","type":"blocks","created_at":"2026-06-28T11:25:09Z","created_by":"Sibin Grasic","metadata":"{}"},{"issue_id":"srbtranslatin-68s","depends_on_id":"srbtranslatin-d40","type":"blocks","created_at":"2026-06-28T11:25:15Z","created_by":"Sibin Grasic","metadata":"{}"},{"issue_id":"srbtranslatin-68s","depends_on_id":"srbtranslatin-ei8","type":"blocks","created_at":"2026-06-28T11:25:05Z","created_by":"Sibin Grasic","metadata":"{}"}],"dependency_count":4,"dependent_count":1,"comment_count":0}
19
{"id":"srbtranslatin-nuq","title":"Analyze and commit current changes","description":"Review the current working tree changes, run the relevant verification, and commit them intentionally.","status":"closed","priority":2,"issue_type":"task","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-06-28T08:38:07Z","created_by":"Sibin Grasic","updated_at":"2026-06-28T08:39:56Z","started_at":"2026-06-28T08:38:17Z","closed_at":"2026-06-28T08:39:56Z","close_reason":"Reviewed current changes, ran verification, and prepared repository commit.","dependency_count":0,"dependent_count":0,"comment_count":0}
210
{"id":"srbtranslatin-beg","title":"Gate transliteration by supported locale","description":"Implement the initialization gate fix so Latin-script transliteration only runs for legacy supported locales, with unit coverage for supported and unsupported locales.","status":"closed","priority":2,"issue_type":"bug","assignee":"Sibin Grasic","owner":"sibin.grasic@oblak.studio","created_at":"2026-06-28T08:31:35Z","created_by":"Sibin Grasic","updated_at":"2026-06-28T08:34:13Z","started_at":"2026-06-28T08:31:39Z","closed_at":"2026-06-28T08:34:13Z","close_reason":"Implemented supported-locale gate for transliteration and added unit coverage.","dependency_count":0,"dependent_count":0,"comment_count":0}
11+
{"id":"srbtranslatin-5ji","title":"Allow alternate test MySQL host port","description":"composer test:install can fail before the installer runs when host port 34110 is already allocated. The installer already accepts DB_PORT, but docker-compose.yml hardcodes 34110:3306. Make the compose host port configurable or auto-detected so the test environment can start when the default port is occupied.","status":"open","priority":3,"issue_type":"bug","owner":"sibin.grasic@oblak.studio","created_at":"2026-06-28T11:20:36Z","created_by":"Sibin Grasic","updated_at":"2026-06-28T11:20:36Z","dependency_count":0,"dependent_count":0,"comment_count":0}

bin/install-wp-tests.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ WP_DOWNLOADS_DIR="${CACHE_DIR}/wp-tests/downloads"
1010
PLUGIN_SLUG="srbtranslatin"
1111
PLUGIN_SOURCE_DIR="${REPO_ROOT}"
1212
PLUGIN_TARGET_DIR="${WP_CORE_DIR}/wp-content/plugins/${PLUGIN_SLUG}"
13+
WP_CLI_BIN="${WP_CLI_BIN:-wp}"
1314

1415
# Support WP_TESTS_DB_HOST (host:port) from CI environments.
1516
if [ -n "${WP_TESTS_DB_HOST:-}" ]; then
@@ -32,7 +33,7 @@ log() {
3233
}
3334

3435
wp_cli() {
35-
php -d memory_limit=512M "$(command -v wp)" "$@"
36+
WP_CLI_PHP_ARGS="${WP_CLI_PHP_ARGS:--d memory_limit=512M}" "${WP_CLI_BIN}" "$@"
3637
}
3738

3839
require_command() {
@@ -190,7 +191,7 @@ main() {
190191
require_command mysqladmin
191192
require_command php
192193
require_command unzip
193-
require_command wp
194+
require_command "${WP_CLI_BIN}"
194195

195196
if [ -z "${WP_TESTS_SKIP_DOCKER:-}" ]; then
196197
require_command docker
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Yoast\PHPUnitPolyfills\TestCases\TestCase;
6+
7+
final class InstallWpTestsScriptTest extends TestCase {
8+
private string $tmp_dir;
9+
10+
protected function set_up(): void {
11+
parent::set_up();
12+
13+
$tmp = tempnam(sys_get_temp_dir(), 'stl-wp-cli-');
14+
15+
if (false === $tmp) {
16+
$this->fail('Unable to create a temporary path.');
17+
}
18+
19+
unlink($tmp);
20+
mkdir($tmp);
21+
22+
$this->tmp_dir = $tmp;
23+
}
24+
25+
protected function tear_down(): void {
26+
$this->removeDirectory($this->tmp_dir);
27+
28+
parent::tear_down();
29+
}
30+
31+
public function test_wp_cli_executes_composer_proxy_as_a_command(): void {
32+
$wp_bin = $this->tmp_dir . '/wp';
33+
34+
file_put_contents(
35+
$wp_bin,
36+
<<<'BASH'
37+
#!/usr/bin/env bash
38+
if [ "$1" = "core" ] && [ "$2" = "version" ]; then
39+
printf '6.5.5\n'
40+
exit 0
41+
fi
42+
43+
exit 12
44+
BASH
45+
);
46+
chmod($wp_bin, 0755);
47+
48+
$source = file_get_contents(dirname(__DIR__, 3) . '/bin/install-wp-tests.sh');
49+
50+
if (false === $source) {
51+
$this->fail('Unable to read bin/install-wp-tests.sh.');
52+
}
53+
54+
$probe = preg_replace('/\nmain "\$@"\s*$/', "\nwp_cli core version\n", $source, 1, $replacements);
55+
56+
$this->assertSame(1, $replacements, 'Expected to replace the installer entry point.');
57+
$this->assertIsString($probe);
58+
59+
$probe_path = $this->tmp_dir . '/probe.sh';
60+
file_put_contents($probe_path, $probe);
61+
chmod($probe_path, 0755);
62+
63+
$result = $this->runProcess(['bash', $probe_path], [
64+
'PATH' => $this->tmp_dir . PATH_SEPARATOR . (string) getenv('PATH'),
65+
]);
66+
67+
$this->assertSame('', $result['stderr']);
68+
$this->assertSame(0, $result['exit_code']);
69+
$this->assertSame("6.5.5\n", $result['stdout']);
70+
}
71+
72+
/**
73+
* @param list<string> $command
74+
* @param array<string, string> $environment
75+
* @return array{exit_code: int, stdout: string, stderr: string}
76+
*/
77+
private function runProcess(array $command, array $environment): array {
78+
$process = proc_open(
79+
$command,
80+
[
81+
1 => ['pipe', 'w'],
82+
2 => ['pipe', 'w'],
83+
],
84+
$pipes,
85+
dirname(__DIR__, 3),
86+
array_merge($_ENV, $environment),
87+
);
88+
89+
if (! is_resource($process)) {
90+
$this->fail('Unable to start process.');
91+
}
92+
93+
$stdout = stream_get_contents($pipes[1]);
94+
$stderr = stream_get_contents($pipes[2]);
95+
96+
fclose($pipes[1]);
97+
fclose($pipes[2]);
98+
99+
return [
100+
'exit_code' => proc_close($process),
101+
'stdout' => false === $stdout ? '' : $stdout,
102+
'stderr' => false === $stderr ? '' : $stderr,
103+
];
104+
}
105+
106+
private function removeDirectory(string $path): void {
107+
if (! is_dir($path)) {
108+
return;
109+
}
110+
111+
$items = scandir($path);
112+
113+
if (false === $items) {
114+
return;
115+
}
116+
117+
foreach ($items as $item) {
118+
if ('.' === $item || '..' === $item) {
119+
continue;
120+
}
121+
122+
$child = $path . DIRECTORY_SEPARATOR . $item;
123+
124+
if (is_dir($child) && ! is_link($child)) {
125+
$this->removeDirectory($child);
126+
continue;
127+
}
128+
129+
unlink($child);
130+
}
131+
132+
rmdir($path);
133+
}
134+
}

0 commit comments

Comments
 (0)