Skip to content

Commit dd9625f

Browse files
Merge branch 'trunk' into f26d/more-lenient-disable-functions
2 parents 928bec3 + ddc9765 commit dd9625f

68 files changed

Lines changed: 3741 additions & 1490 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.buildkite/commands/run-e2e-tests.sh‎

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,15 @@ if [ "$PLATFORM" = "linux" ]; then
152152
# right-edge content (e.g. the preferences Save button) below the fold
153153
# for the split-pane settings layout. 1920x1080 matches a typical
154154
# desktop and avoids relying on scroll-into-view.
155+
inner_exit=0
155156
xvfb-run -a -s "-screen 0 1920x1080x24" \
156-
npx playwright test --max-failures=1 --output=/tmp/test-results
157+
npx playwright test --max-failures=1 --output=/tmp/test-results || inner_exit=$?
158+
# On failure, collect daemon logs into /tmp/test-results (copied to the
159+
# artifact dir below). $HOME here is the node user that ran the tests.
160+
if [ "$inner_exit" -ne 0 ] && [ -d "$HOME/.studio/daemon/logs" ]; then
161+
cp -r "$HOME/.studio/daemon/logs" /tmp/test-results/daemon-logs || true
162+
fi
163+
exit "$inner_exit"
157164
' || test_exit=$?
158165

159166
if [ -d /tmp/test-results ]; then
@@ -168,5 +175,15 @@ else
168175
npx playwright install
169176

170177
echo 'Running Playwright tests...'
171-
npx playwright test
178+
# Capture the exit code so a failure doesn't trip `set -e` before we collect
179+
# the daemon logs (~/.studio/daemon/logs) for artifact upload.
180+
test_exit=0
181+
npx playwright test || test_exit=$?
182+
183+
if [ "$test_exit" -ne 0 ] && [ -d "$HOME/.studio/daemon/logs" ]; then
184+
mkdir -p test-results/daemon-logs
185+
cp -r "$HOME/.studio/daemon/logs/." test-results/daemon-logs/ || true
186+
fi
187+
188+
exit "$test_exit"
172189
fi

‎.buildkite/pipeline.yml‎

Lines changed: 101 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ e2e_config: &e2e_config
1212
- test-results/**/*.zip
1313
- test-results/**/*.png
1414
- test-results/**/*error-context.md
15+
- test-results/daemon-logs/**/*.log
1516
plugins: [$CI_TOOLKIT_PLUGIN, $NVM_PLUGIN]
1617
agents:
1718
queue: "{{matrix.platform}}"
@@ -48,77 +49,111 @@ steps:
4849
- github_commit_status:
4950
context: fastlane Helper Tests
5051

51-
- label: Unit Tests on {{matrix}}
52-
key: unit_tests
53-
command: bash .buildkite/commands/run-unit-tests.sh "{{matrix}}"
54-
plugins: [$CI_TOOLKIT_PLUGIN, $NVM_PLUGIN]
55-
agents:
56-
queue: "{{matrix}}"
57-
matrix:
58-
- mac
59-
- windows
60-
notify:
61-
- github_commit_status:
62-
context: Unit Tests
63-
64-
# Linux unit tests run on the shared `default` queue inside a Debian Node
65-
# container — the same pattern the Linux build group uses. Kept as a
66-
# separate step (rather than another matrix entry above) because Mac and
67-
# Windows share queue/plugin defaults that Linux doesn't.
68-
- label: Unit Tests on linux
69-
key: unit_tests_linux
70-
command: bash .buildkite/commands/run-unit-tests.sh "linux"
71-
agents:
72-
queue: default
73-
plugins:
74-
- $DOCKER_PLUGIN:
75-
image: "$NODE_DOCKER_IMAGE"
76-
propagate-environment: true
77-
mount-buildkite-agent: true
78-
notify:
79-
- github_commit_status:
80-
context: Unit Tests
81-
82-
# E2E tests run on supported platform/architecture combinations.
83-
# - mac-arm64: Native on Apple Silicon agents
84-
# - windows-x64: Native on x64 agents
85-
- <<: *e2e_config
86-
label: E2E Tests on {{matrix.platform}}-{{matrix.arch}}
87-
key: e2e_tests
88-
# TEMP(rsm-2593): if: removed to force E2E on every push while iterating on Linux E2E setup. Revert before merge.
89-
90-
- <<: *e2e_config
91-
label: E2E Tests on {{matrix.platform}}-{{matrix.arch}} with native PHP
92-
key: e2e_tests_native_php
93-
env:
94-
DEBUG: "pw:browser"
95-
STUDIO_RUNTIME: native-php
96-
if: (build.branch == 'trunk' || build.tag =~ /^v[0-9]+/ || !build.pull_request.draft) && build.pull_request.labels includes 'native-php'
52+
- group: Unit Tests
53+
key: unit-tests
54+
steps:
55+
- label: Unit Tests on {{matrix}}
56+
key: unit_tests
57+
command: bash .buildkite/commands/run-unit-tests.sh "{{matrix}}"
58+
plugins: [$CI_TOOLKIT_PLUGIN, $NVM_PLUGIN]
59+
agents:
60+
queue: "{{matrix}}"
61+
matrix:
62+
- mac
63+
- windows
64+
notify:
65+
- github_commit_status:
66+
context: Unit Tests
67+
68+
# Linux unit tests run on the shared `default` queue inside a Debian Node
69+
# container — the same pattern the Linux build group uses. Kept as a
70+
# separate step (rather than another matrix entry above) because Mac and
71+
# Windows share queue/plugin defaults that Linux doesn't.
72+
- label: Unit Tests on linux
73+
key: unit_tests_linux
74+
command: bash .buildkite/commands/run-unit-tests.sh "linux"
75+
agents:
76+
queue: default
77+
plugins:
78+
- $DOCKER_PLUGIN:
79+
image: "$NODE_DOCKER_IMAGE"
80+
propagate-environment: true
81+
mount-buildkite-agent: true
82+
notify:
83+
- github_commit_status:
84+
context: Unit Tests
85+
86+
- group: E2E Tests
87+
key: e2e-tests
88+
steps:
89+
# E2E tests run on supported platform/architecture combinations.
90+
# - mac-arm64: Native on Apple Silicon agents
91+
# - windows-x64: Native on x64 agents
92+
- <<: *e2e_config
93+
label: E2E Tests on {{matrix.platform}}-{{matrix.arch}}
94+
key: e2e_tests
95+
# TEMP(rsm-2593): if: removed to force E2E on every push while iterating on Linux E2E setup. Revert before merge.
96+
97+
- <<: *e2e_config
98+
label: E2E Tests on {{matrix.platform}}-{{matrix.arch}} with native PHP
99+
key: e2e_tests_native_php
100+
env:
101+
DEBUG: "pw:browser"
102+
STUDIO_RUNTIME: native-php
103+
if: (build.branch == 'trunk' || build.tag =~ /^v[0-9]+/ || !build.pull_request.draft) && build.pull_request.labels includes 'native-php'
97104

98105
# Linux E2E tests run on the shared `default` queue inside a Debian Node
99106
# container — the same pattern the Linux build/unit-test steps use. Kept as
100107
# a separate step (rather than another matrix entry on *e2e_config) because
101108
# Mac and Windows share queue/plugin defaults that Linux doesn't.
102-
- label: E2E Tests on linux-x64
103-
key: e2e_tests_linux
104-
command: bash .buildkite/commands/run-e2e-tests.sh "linux" "x64"
105-
agents:
106-
queue: default
107-
plugins:
108-
- $DOCKER_PLUGIN:
109-
image: "$NODE_DOCKER_IMAGE"
110-
propagate-environment: true
111-
mount-buildkite-agent: true
112-
artifact_paths:
113-
- test-results/**/*.zip
114-
- test-results/**/*.png
115-
- test-results/**/*error-context.md
116-
env:
117-
DEBUG: "pw:browser"
118-
# TEMP(rsm-2593): if: removed to force E2E on every push while iterating on Linux E2E setup. Revert before merge.
119-
notify:
120-
- github_commit_status:
121-
context: E2E Tests
109+
# Linux E2E tests run on the shared `default` queue inside a Debian Node
110+
# container — the same pattern the Linux build/unit-test steps use. Kept as
111+
# a separate step (rather than another matrix entry on *e2e_config) because
112+
# Mac and Windows share queue/plugin defaults that Linux doesn't.
113+
- label: E2E Tests on linux-x64
114+
key: e2e_tests_linux
115+
command: bash .buildkite/commands/run-e2e-tests.sh "linux" "x64"
116+
agents:
117+
queue: default
118+
plugins:
119+
- $DOCKER_PLUGIN:
120+
image: "$NODE_DOCKER_IMAGE"
121+
propagate-environment: true
122+
mount-buildkite-agent: true
123+
artifact_paths:
124+
- test-results/**/*.zip
125+
- test-results/**/*.png
126+
- test-results/**/*error-context.md
127+
- test-results/daemon-logs/**/*.log
128+
env:
129+
DEBUG: "pw:browser"
130+
# TEMP(rsm-2593): if: removed to force E2E on every push while iterating on Linux E2E setup. Revert before merge.
131+
notify:
132+
- github_commit_status:
133+
context: E2E Tests
134+
135+
- label: E2E Tests on linux-x64 with native PHP
136+
key: e2e_tests_linux_native_php
137+
command: bash .buildkite/commands/run-e2e-tests.sh "linux" "x64"
138+
agents:
139+
queue: default
140+
plugins:
141+
- $DOCKER_PLUGIN:
142+
image: "$NODE_DOCKER_IMAGE"
143+
propagate-environment: true
144+
mount-buildkite-agent: true
145+
artifact_paths:
146+
- test-results/**/*.zip
147+
- test-results/**/*.png
148+
- test-results/**/*error-context.md
149+
- test-results/daemon-logs/**/*.log
150+
env:
151+
DEBUG: "pw:browser"
152+
STUDIO_RUNTIME: native-php
153+
if: (build.branch == 'trunk' || build.tag =~ /^v[0-9]+/ || !build.pull_request.draft) && build.pull_request.labels includes 'native-php'
154+
notify:
155+
- github_commit_status:
156+
context: E2E Tests
122157

123158
- label: ":chart_with_upwards_trend: Performance Metrics"
124159
key: metrics

‎apps/cli/ai/sessions/context.ts‎

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isAiModelId, type AiModelId } from '@studio/common/ai/models';
1+
import { resolveSessionModel, type AiModelId } from '@studio/common/ai/models';
22
import { isStudioCustomEntryOfType } from '@studio/common/ai/sessions/entry-types';
33
import { AI_PROVIDERS, type AiProviderId } from 'cli/ai/providers';
44
import type { LoadedAiSession } from '@studio/common/ai/sessions/types';
@@ -27,31 +27,21 @@ export function resolveResumeSessionContext(
2727
context.sessionId = resumeSession.summary.id;
2828
}
2929

30+
// Shared resolution: the most recent recorded model wins, and a removed
31+
// model auto-switches to the default so resumed sessions never pin a
32+
// model we no longer offer.
33+
context.model = resolveSessionModel( resumeSession.entries );
34+
3035
for ( let index = resumeSession.entries.length - 1; index >= 0; index -= 1 ) {
3136
const entry = resumeSession.entries[ index ];
3237

33-
if ( ! context.model && entry.type === 'model_change' ) {
34-
const modelId = ( entry as { modelId?: unknown } ).modelId;
35-
if ( typeof modelId === 'string' && isAiModelId( modelId ) ) {
36-
context.model = modelId;
37-
}
38-
}
39-
4038
if ( isStudioCustomEntryOfType( entry, 'studio.session_context' ) ) {
4139
const data = entry.data;
42-
if ( data ) {
43-
if ( ! context.provider && isAiProviderId( data.provider ) ) {
44-
context.provider = data.provider;
45-
}
46-
if ( ! context.model && isAiModelId( data.model ) ) {
47-
context.model = data.model;
48-
}
40+
if ( data && isAiProviderId( data.provider ) ) {
41+
context.provider = data.provider;
42+
break;
4943
}
5044
}
51-
52-
if ( context.sessionId && context.provider && context.model ) {
53-
break;
54-
}
5545
}
5646

5747
return context;

‎apps/cli/commands/wp.ts‎

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import { connectToDaemon, disconnectFromDaemon } from 'cli/lib/daemon-client';
1111
import { getPhpBinaryPath, getWpCliPharPath } from 'cli/lib/dependency-management/paths';
1212
import { ensurePhpBinaryAvailable } from 'cli/lib/dependency-management/php-binary';
1313
import { getSiteRuntime } from 'cli/lib/feature-flags';
14-
import { getDefaultPhpArgs } from 'cli/lib/native-php';
14+
import { getDefaultPhpArgs } from 'cli/lib/native-php/config';
15+
import { DETACH_FOR_GROUP_KILL, reapPhpTreeOnInterrupt } from 'cli/lib/native-php/php-process';
1516
import { runWpCliCommand, runGlobalWpCliCommand, WpCliResponse } from 'cli/lib/run-wp-cli-command';
1617
import { validatePhpVersion } from 'cli/lib/utils';
1718
import { isServerRunning, sendWpCliCommand } from 'cli/lib/wordpress-server-manager';
@@ -58,18 +59,28 @@ async function runNativePhpWpCliCommand( site: SiteData, args: string[] ): Promi
5859
{
5960
cwd: site.path,
6061
stdio: 'inherit',
62+
detached: DETACH_FOR_GROUP_KILL,
6163
}
6264
);
6365

64-
const { code, signal } = await new Promise< {
65-
code: number | null;
66-
signal: NodeJS.Signals | null;
67-
} >( ( resolve, reject ) => {
68-
child.once( 'error', reject );
69-
child.once( 'exit', ( exitCode, exitSignal ) =>
70-
resolve( { code: exitCode, signal: exitSignal } )
71-
);
72-
} );
66+
// Reap php.exe and any subprocess it spawned if this command is interrupted before the child exits.
67+
const removeReaper = reapPhpTreeOnInterrupt( child );
68+
69+
let code: number | null;
70+
let signal: NodeJS.Signals | null;
71+
try {
72+
( { code, signal } = await new Promise< {
73+
code: number | null;
74+
signal: NodeJS.Signals | null;
75+
} >( ( resolve, reject ) => {
76+
child.once( 'error', reject );
77+
child.once( 'exit', ( exitCode, exitSignal ) =>
78+
resolve( { code: exitCode, signal: exitSignal } )
79+
);
80+
} ) );
81+
} finally {
82+
removeReaper();
83+
}
7384

7485
if ( signal ) {
7586
process.kill( process.pid, signal );

‎apps/cli/lib/dependency-management/php-binary.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
type PhpBinaryDownloadInfo,
1212
type NativePhpSupportedVersion,
1313
} from '@studio/common/lib/php-binary-metadata';
14-
import { ensureNativePhpIniFiles } from '../native-php';
14+
import { ensureNativePhpIniFiles } from 'cli/lib/native-php/config';
1515
import { getPhpBinaryPath } from './paths';
1616
import type { SupportedPHPVersion } from '@studio/common/types/php-versions';
1717

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import os from 'os';
44
import path from 'path';
55
import { NativePhpSupportedVersion } from '@studio/common/lib/php-binary-metadata';
66
import { writeFile } from 'atomically';
7-
import { getPhpBinaryPath } from './dependency-management/paths';
7+
import semver from 'semver';
8+
import { getPhpBinaryPath } from '../dependency-management/paths';
89

910
// Disabled to shrink the attack surface available to PHP code running inside a
1011
// Studio site. Each entry falls into one of:
@@ -169,9 +170,14 @@ export function getNativePhpIniContents( phpVersion: NativePhpSupportedVersion )
169170
if ( process.platform === 'win32' ) {
170171
directives.push(
171172
`extension_dir="${ toPhpIniPath( getExtensionDir( phpVersion ) ) }"`,
172-
'zend_extension=opcache',
173173
...WINDOWS_PHP_EXTENSIONS.map( ( extension ) => `extension=${ extension }` )
174174
);
175+
176+
const coercedVersion = semver.coerce( phpVersion );
177+
// As of PHP 8.5, the OPcache extension is always bundled with PHP
178+
if ( coercedVersion && semver.lt( coercedVersion, '8.5.0' ) ) {
179+
directives.push( 'zend_extension=opcache' );
180+
}
175181
}
176182

177183
return `${ directives.join( os.EOL ) }${ os.EOL }`;

0 commit comments

Comments
 (0)