Fix TCC dialog, trim black frames, add macos-26 runner option (#784)
- Grant kTCCServiceScreenCapture in system-level TCC database (sudo) and pre-date ScreenCaptureApprovals.plist to suppress Sequoia's private window picker dialog - Move recording start to right before xcodebuild test (skip build time) - Trim leading black frames from video using ffmpeg blackdetect - Add runner input: macos-15 (Sequoia) or macos-26 (Tahoe)
This commit is contained in:
parent
d77299c220
commit
37dc43a6de
1 changed files with 90 additions and 51 deletions
141
.github/workflows/test-e2e.yml
vendored
141
.github/workflows/test-e2e.yml
vendored
|
|
@ -19,10 +19,18 @@ on:
|
|||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
runner:
|
||||
description: "Runner OS (macos-15 or macos-26)"
|
||||
required: false
|
||||
default: "macos-15"
|
||||
type: choice
|
||||
options:
|
||||
- macos-15
|
||||
- macos-26
|
||||
|
||||
jobs:
|
||||
e2e:
|
||||
runs-on: macos-15
|
||||
runs-on: ${{ inputs.runner || 'macos-15' }}
|
||||
env:
|
||||
TEST_REF: ${{ inputs.ref || github.ref }}
|
||||
steps:
|
||||
|
|
@ -107,56 +115,38 @@ jobs:
|
|||
echo "FFMPEG_PATH=$FFMPEG_PATH" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Grant TCC screen recording permission
|
||||
if: ${{ inputs.record_video }}
|
||||
continue-on-error: true
|
||||
run: |
|
||||
TCC_DB="$HOME/Library/Application Support/com.apple.TCC/TCC.db"
|
||||
if [ -f "$TCC_DB" ]; then
|
||||
for client in /usr/sbin/screencapture "${FFMPEG_PATH:-/opt/homebrew/bin/ffmpeg}" /opt/homebrew/bin/ffmpeg /usr/local/bin/ffmpeg; do
|
||||
sqlite3 "$TCC_DB" "INSERT OR REPLACE INTO access (service, client, client_type, auth_value, auth_reason, auth_version) VALUES ('kTCCServiceScreenCapture', '$client', 1, 2, 4, 1);" 2>/dev/null || true
|
||||
FFMPEG_BIN="${FFMPEG_PATH:-/opt/homebrew/bin/ffmpeg}"
|
||||
|
||||
# System-level TCC database (where kTCCServiceScreenCapture lives)
|
||||
SYS_TCC="/Library/Application Support/com.apple.TCC/TCC.db"
|
||||
if [ -f "$SYS_TCC" ]; then
|
||||
echo "Granting screen capture in system TCC database"
|
||||
for client in "$FFMPEG_BIN" /opt/homebrew/bin/ffmpeg /usr/local/bin/ffmpeg /usr/sbin/screencapture; do
|
||||
sudo sqlite3 "$SYS_TCC" \
|
||||
"INSERT OR REPLACE INTO access (service, client, client_type, auth_value, auth_reason, auth_version, csreq, policy_id, indirect_object_identifier_type, indirect_object_identifier, indirect_object_code_identity, flags, last_modified) VALUES ('kTCCServiceScreenCapture', '$client', 1, 2, 4, 1, NULL, NULL, 0, 'UNUSED', NULL, 0, $(date +%s));" 2>&1 || echo " (failed for $client)"
|
||||
done
|
||||
fi
|
||||
|
||||
- name: Start screen recording
|
||||
if: ${{ inputs.record_video }}
|
||||
run: |
|
||||
# Detect screen capture device index. ffmpeg -list_devices always
|
||||
# exits non-zero; redirect noise to a temp file and parse it.
|
||||
DEVLIST=$( ffmpeg -f avfoundation -list_devices true -i "" 2>&1 || true )
|
||||
echo "Available devices:"
|
||||
echo "$DEVLIST" | grep -E "AVFoundation|Capture screen"
|
||||
|
||||
SCREEN_INDEX=$( echo "$DEVLIST" | grep "Capture screen" | head -1 \
|
||||
| sed 's/.*\[\([0-9]*\)\].*/\1/' )
|
||||
SCREEN_INDEX="${SCREEN_INDEX:-0}"
|
||||
echo "Using screen device index: $SCREEN_INDEX"
|
||||
|
||||
# Start recording. Try detected index, fall back to 1 if it dies immediately.
|
||||
start_recording() {
|
||||
ffmpeg -f avfoundation -framerate 10 -capture_cursor 1 \
|
||||
-i "$1:none" \
|
||||
-c:v libx264 -preset ultrafast -pix_fmt yuv420p \
|
||||
/tmp/test-recording.mp4 </dev/null >/tmp/ffmpeg.log 2>&1 &
|
||||
echo $!
|
||||
}
|
||||
|
||||
RECORD_PID=$(start_recording "$SCREEN_INDEX")
|
||||
sleep 2
|
||||
|
||||
if ! kill -0 "$RECORD_PID" 2>/dev/null; then
|
||||
echo "Index $SCREEN_INDEX failed, trying index 1"
|
||||
cat /tmp/ffmpeg.log
|
||||
rm -f /tmp/test-recording.mp4
|
||||
RECORD_PID=$(start_recording 1)
|
||||
sleep 2
|
||||
# User-level TCC database (fallback)
|
||||
USER_TCC="$HOME/Library/Application Support/com.apple.TCC/TCC.db"
|
||||
if [ -f "$USER_TCC" ]; then
|
||||
echo "Granting screen capture in user TCC database"
|
||||
for client in "$FFMPEG_BIN" /opt/homebrew/bin/ffmpeg /usr/local/bin/ffmpeg; do
|
||||
sqlite3 "$USER_TCC" \
|
||||
"INSERT OR REPLACE INTO access (service, client, client_type, auth_value, auth_reason, auth_version, csreq, policy_id, indirect_object_identifier_type, indirect_object_identifier, indirect_object_code_identity, flags, last_modified) VALUES ('kTCCServiceScreenCapture', '$client', 1, 2, 4, 1, NULL, NULL, 0, 'UNUSED', NULL, 0, $(date +%s));" 2>&1 || echo " (failed for $client)"
|
||||
done
|
||||
fi
|
||||
|
||||
if kill -0 "$RECORD_PID" 2>/dev/null; then
|
||||
echo "Recording started (PID $RECORD_PID)"
|
||||
else
|
||||
echo "::error::ffmpeg screen recording failed to start"
|
||||
cat /tmp/ffmpeg.log
|
||||
# Suppress Sequoia's ScreenCaptureApprovals prompt by pre-dating approval
|
||||
APPROVALS_PLIST="$HOME/Library/Group Containers/group.com.apple.replayd/ScreenCaptureApprovals.plist"
|
||||
if [ -d "$(dirname "$APPROVALS_PLIST")" ]; then
|
||||
echo "Pre-dating ScreenCaptureApprovals"
|
||||
# Set approval date far in the future so the monthly prompt never fires
|
||||
defaults write "$APPROVALS_PLIST" "$FFMPEG_BIN" -date "3000-01-01T00:00:00Z" 2>&1 || echo " (failed)"
|
||||
fi
|
||||
echo "RECORD_PID=$RECORD_PID" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Clean DerivedData
|
||||
run: rm -rf ~/Library/Developer/Xcode/DerivedData/GhosttyTabs-*
|
||||
|
|
@ -186,12 +176,39 @@ jobs:
|
|||
env:
|
||||
TEST_FILTER: ${{ inputs.test_filter }}
|
||||
TEST_TIMEOUT: ${{ inputs.test_timeout || '120' }}
|
||||
RECORD_VIDEO: ${{ inputs.record_video }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
SOURCE_PACKAGES_DIR="$PWD/.ci-source-packages"
|
||||
|
||||
ONLY_TESTING="-only-testing:cmuxUITests/$TEST_FILTER"
|
||||
|
||||
# Start recording right before the test (after build/resolve)
|
||||
if [ "$RECORD_VIDEO" = "true" ]; then
|
||||
DEVLIST=$( ffmpeg -f avfoundation -list_devices true -i "" 2>&1 || true )
|
||||
echo "Available devices:"
|
||||
echo "$DEVLIST" | grep -E "AVFoundation|Capture screen"
|
||||
|
||||
SCREEN_INDEX=$( echo "$DEVLIST" | grep "Capture screen" | head -1 \
|
||||
| sed 's/.*\[\([0-9]*\)\].*/\1/' )
|
||||
SCREEN_INDEX="${SCREEN_INDEX:-0}"
|
||||
echo "Using screen device index: $SCREEN_INDEX"
|
||||
|
||||
ffmpeg -f avfoundation -framerate 10 -capture_cursor 1 \
|
||||
-i "${SCREEN_INDEX}:none" \
|
||||
-c:v libx264 -preset ultrafast -pix_fmt yuv420p \
|
||||
/tmp/test-recording-raw.mp4 </dev/null >/tmp/ffmpeg.log 2>&1 &
|
||||
RECORD_PID=$!
|
||||
echo "RECORD_PID=$RECORD_PID" >> "$GITHUB_ENV"
|
||||
sleep 2
|
||||
|
||||
if kill -0 "$RECORD_PID" 2>/dev/null; then
|
||||
echo "Recording started (PID $RECORD_PID)"
|
||||
else
|
||||
echo "::warning::ffmpeg screen recording failed to start"
|
||||
cat /tmp/ffmpeg.log
|
||||
fi
|
||||
fi
|
||||
|
||||
set +e
|
||||
OUTPUT=$(xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug \
|
||||
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES_DIR" \
|
||||
|
|
@ -225,10 +242,10 @@ jobs:
|
|||
exit 1
|
||||
fi
|
||||
|
||||
- name: Stop screen recording
|
||||
- name: Stop recording and trim
|
||||
if: ${{ always() && inputs.record_video && env.RECORD_PID != '' }}
|
||||
run: |
|
||||
# Send quit signal to ffmpeg for clean finalization
|
||||
# Stop ffmpeg cleanly
|
||||
kill -INT "$RECORD_PID" 2>/dev/null || true
|
||||
for i in $(seq 1 15); do
|
||||
if ! kill -0 "$RECORD_PID" 2>/dev/null; then
|
||||
|
|
@ -238,10 +255,33 @@ jobs:
|
|||
sleep 1
|
||||
done
|
||||
kill -9 "$RECORD_PID" 2>/dev/null || true
|
||||
echo "=== ffmpeg log ==="
|
||||
cat /tmp/ffmpeg.log 2>/dev/null || true
|
||||
echo "=== recording file ==="
|
||||
ls -lh /tmp/test-recording.mp4 2>/dev/null || echo "No recording file found"
|
||||
|
||||
echo "=== raw recording ==="
|
||||
ls -lh /tmp/test-recording-raw.mp4 2>/dev/null || { echo "No recording file"; exit 0; }
|
||||
|
||||
# Trim: detect first non-black frame and cut from there
|
||||
BLACK_END=$(ffmpeg -i /tmp/test-recording-raw.mp4 \
|
||||
-vf "blackdetect=d=0.3:pic_th=0.95:pix_th=0.1" \
|
||||
-an -f null - 2>&1 \
|
||||
| grep "black_end" | tail -1 \
|
||||
| sed 's/.*black_end:\([0-9.]*\).*/\1/' || true)
|
||||
|
||||
if [ -n "$BLACK_END" ] && [ "$BLACK_END" != "0" ]; then
|
||||
echo "Trimming ${BLACK_END}s of black frames from start"
|
||||
ffmpeg -y -i /tmp/test-recording-raw.mp4 -ss "$BLACK_END" \
|
||||
-c:v libx264 -preset ultrafast -pix_fmt yuv420p \
|
||||
/tmp/test-recording.mp4 2>/dev/null
|
||||
else
|
||||
echo "No black frames detected, using raw recording"
|
||||
mv /tmp/test-recording-raw.mp4 /tmp/test-recording.mp4
|
||||
fi
|
||||
|
||||
echo "=== final recording ==="
|
||||
ls -lh /tmp/test-recording.mp4
|
||||
# Print duration
|
||||
ffprobe -v error -show_entries format=duration \
|
||||
-of default=noprint_wrappers=1:nokey=1 /tmp/test-recording.mp4 2>/dev/null \
|
||||
| xargs -I{} echo "Duration: {}s"
|
||||
|
||||
- name: Upload recording artifact
|
||||
if: ${{ always() && inputs.record_video }}
|
||||
|
|
@ -276,7 +316,6 @@ jobs:
|
|||
RUN_URL="https://github.com/${{ github.repository }}/actions/runs/$RUN_ID"
|
||||
ARTIFACT_URL="$RUN_URL#artifacts"
|
||||
|
||||
# Build issue body (no leading whitespace)
|
||||
BODY="**Status:** $STATUS_EMOJI
|
||||
**Ref:** \`$REF_DISPLAY\`
|
||||
**SHA:** [\`${COMMIT_SHA:0:12}\`](https://github.com/${{ github.repository }}/commit/$COMMIT_SHA)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue