Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

This repository contains the libtmux gem suite. Installed-import
tests establish package boundaries and execute consumer APIs and documentation
recipes. Compatibility CI records the exact Ruby, tmux and operating-system cells.
recipes. Compatibility CI records the exact Ruby and tmux cells on Linux.
macOS is supported on a best-effort basis, and CI coverage for it is highly
limited: no job runs there, so a macOS-only regression is not caught before
merge.

Read [AGENTS.md](../AGENTS.md) for change discipline and [WRITING.md](WRITING.md)
for prose and commit conventions.
Expand All @@ -22,7 +25,7 @@ which tmux 3.2 clients cannot start; it also needs
variable to `refused` or `supported` for the other version check tests, and
they fail in CI when it is missing.
The authored-shell tests use zsh's ZLE, `zsh/net/socket` and `zsh/system`
modules. The Linux CI job installs zsh; the macOS runner supplies it.
modules. The Linux CI job installs zsh.

Install the pinned tool with mise:

Expand Down
94 changes: 0 additions & 94 deletions .github/scripts/trace-process.rb

This file was deleted.

86 changes: 4 additions & 82 deletions .github/workflows/compatibility.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,6 @@ on:
branches: [master]
pull_request:
workflow_dispatch:
inputs:
debug_enabled:
type: boolean
description: Open tmate on the macOS Ruby 4.0.7 / tmux 3.7c cell
default: false
native_only:
type: boolean
description: Run only the macOS Ruby 4.0.7 / tmux 3.7c cell without tmate
default: false

permissions:
contents: read
Expand Down Expand Up @@ -55,9 +46,9 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: ${{ fromJSON(github.event_name == 'workflow_dispatch' && (inputs.debug_enabled || inputs.native_only) && '[{"system":"macos","runner":"macos-15"}]' || '[{"system":"linux","runner":"ubuntu-24.04"},{"system":"macos","runner":"macos-15"}]') }}
ruby: ${{ fromJSON(github.event_name == 'workflow_dispatch' && (inputs.debug_enabled || inputs.native_only) && '["4.0.7"]' || '["3.3.12","3.4.10","4.0.7"]') }}
tmux: ${{ fromJSON(github.event_name == 'workflow_dispatch' && (inputs.debug_enabled || inputs.native_only) && '["3.7c"]' || '["3.3a","3.4","3.5a","3.6","3.7c","3.8"]') }}
platform: [{system: linux, runner: ubuntu-24.04}]
ruby: ['3.3.12', '3.4.10', '4.0.7']
tmux: ['3.3a', '3.4', '3.5a', '3.6', '3.7c', '3.8']
env:
BUNDLE_FROZEN: 'true'
LIBTMUX_VERSION_CHECK_EXPECT: supported
Expand All @@ -78,9 +69,6 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install --yes libevent-dev libncurses-dev bison pkg-config zsh
- name: Install macOS build dependencies
if: runner.os == 'macOS'
run: brew install libevent ncurses bison pkg-config jemalloc
- name: Build the exact tmux release
shell: bash
run: |
Expand All @@ -92,47 +80,11 @@ jobs:
ruby -rjson -rdigest -e 'expected = JSON.parse(File.read("scripts/tmux-releases.json")).fetch(ENV.fetch("TMUX_VERSION")); abort "tmux archive checksum mismatch" unless Digest::SHA256.file(ARGV.fetch(0)).hexdigest == expected' "$archive"
tar -xzf "$archive" -C "$RUNNER_TEMP"
configure_options=(--disable-utf8proc)
if [ "$RUNNER_OS" = macOS ]; then
PATH="$(brew --prefix bison)/bin:$PATH"
PKG_CONFIG_PATH="$(brew --prefix libevent)/lib/pkgconfig:$(brew --prefix ncurses)/lib/pkgconfig"
CPPFLAGS="-I$(brew --prefix libevent)/include -I$(brew --prefix ncurses)/include"
LDFLAGS="-L$(brew --prefix libevent)/lib -L$(brew --prefix ncurses)/lib"
if [ "$TMUX_VERSION" = 3.7c ]; then
PKG_CONFIG_PATH="$(brew --prefix jemalloc)/lib/pkgconfig:$PKG_CONFIG_PATH"
CPPFLAGS="-I$(brew --prefix jemalloc)/include $CPPFLAGS"
LDFLAGS="-L$(brew --prefix jemalloc)/lib $LDFLAGS"
configure_options+=(--enable-jemalloc)
fi
export PATH PKG_CONFIG_PATH CPPFLAGS LDFLAGS
fi
cd "$RUNNER_TEMP/tmux-$TMUX_VERSION"
./configure --prefix="$RUNNER_TEMP/tmux-install" "${configure_options[@]}"
make -j2
make install
test "$("$RUNNER_TEMP/tmux-install/bin/tmux" -V)" = "tmux $TMUX_VERSION"
- name: Trace native child retirement samples
if: ${{ always() && github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
continue-on-error: true
timeout-minutes: 2
shell: bash
run: |
mkdir -p build/native-process-trace
bundle exec ruby .github/scripts/trace-process.rb --compare-waits \
> build/native-process-trace/wait-comparison.json
# Keep every sample and failure; these diagnostics are not a test retry gate.
for sample in 1 2 3 4 5 6; do
if CHILD_TRACE="build/native-process-trace/sample-$sample.json" \
bundle exec ruby -Igems/libtmux/lib -r./.github/scripts/trace-process.rb \
-Itest test/unit/process_test.rb \
--name '/test_cancellation_escalates_and_reaps_a_child_ignoring_term|test_repeated_thread_cancellation_does_not_replace_the_first_failure/' \
> "build/native-process-trace/sample-$sample.log" 2>&1; then
status=0
else
status=$?
fi
printf '{"sample":%d,"exit_status":%d}\n' "$sample" "$status" \
>> build/native-process-trace/samples.jsonl
done
- name: Run the complete cell
timeout-minutes: 5
run: >-
Expand All @@ -148,36 +100,6 @@ jobs:
name: matrix-${{ matrix.platform.system }}-${{ matrix.ruby }}-${{ matrix.tmux }}
path: build/matrix/
if-no-files-found: warn
- name: Retain every native child retirement sample
if: ${{ always() && github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
continue-on-error: true
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: native-process-trace
path: build/native-process-trace/
retention-days: 7
if-no-files-found: error
- name: Debug the selected macOS cell
id: debug
if: ${{ always() && github.event_name == 'workflow_dispatch' && inputs.debug_enabled && matrix.platform.system == 'macos' && matrix.ruby == '4.0.7' && matrix.tmux == '3.7c' }}
uses: mxschmitt/action-tmate@35b54afac29c97fb54faba5b513f8fbd1882f113 # v3
timeout-minutes: 10
with:
detached: true
limit-access-to-actor: true
- name: Save the restricted debug SSH address
if: ${{ always() && github.event_name == 'workflow_dispatch' && inputs.debug_enabled && steps.debug.outputs.ssh-address != '' }}
env:
TMATE_SSH_ADDRESS: ${{ steps.debug.outputs.ssh-address }}
run: printf '%s\n' "$TMATE_SSH_ADDRESS" > "$RUNNER_TEMP/tmate-ssh-address.txt"
- name: Retain the restricted debug connection
if: ${{ always() && github.event_name == 'workflow_dispatch' && inputs.debug_enabled && steps.debug.outputs.ssh-address != '' }}
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: tmate-connection
path: ${{ runner.temp }}/tmate-ssh-address.txt
retention-days: 1
if-no-files-found: error

unsupported:
name: Refuse tmux ${{ matrix.tmux }} before effects
Expand Down Expand Up @@ -276,7 +198,7 @@ jobs:

report:
name: All required cells
if: ${{ always() && !(github.event_name == 'workflow_dispatch' && (inputs.debug_enabled || inputs.native_only)) }}
if: ${{ always() }}
needs: [cell, unsupported, development]
runs-on: ubuntu-24.04
timeout-minutes: 5
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## 0.1.0.alpha.3 (unreleased)

- CI no longer runs macOS. macOS stays supported on a best-effort basis, and CI
coverage for it is highly limited, so a macOS-only regression is not caught
before merge. (#49)

## 0.1.0.alpha.2 (2026-10-18)

Requires tmux 3.3a or newer, checked against the running daemon, and runs on
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,8 +354,9 @@ isolated installation and runs the recipes outside the checkout.
minimum. A [server handle][server] checks the connected daemon's release, not
the client's, and refuses an older daemon before any requested command runs.
- **Linux, including WSL, and macOS.** The [compatibility workflow][compat]
runs Ruby 3.3, 3.4 and 4.0 with tmux 3.3a through 3.8 on Ubuntu 24.04 and
macOS 15.
runs Ruby 3.3, 3.4 and 4.0 with tmux 3.3a through 3.8 on Ubuntu 24.04.
macOS is supported on a best-effort basis, and CI coverage for it is highly
limited.
- **tmux master and old daemons.** On Ubuntu the workflow also runs the suite
against a pinned tmux master, and checks that tmux 3.0a, 3.1c, 3.2a and 3.3
daemons are refused.
Expand Down
5 changes: 3 additions & 2 deletions gems/libtmux-async/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,9 @@ The contract is in [Control connections][behavior-control].
- **Async 2.46.** The gem depends on `async` ~> 2.46.0 and the same version of
`libtmux`.
- **Linux, including WSL, and macOS.** The [compatibility workflow][compat]
runs Ruby 3.3, 3.4 and 4.0 with tmux 3.3a through 3.8 on Ubuntu 24.04 and
macOS 15, and retains per-revision results.
runs Ruby 3.3, 3.4 and 4.0 with tmux 3.3a through 3.8 on Ubuntu 24.04 and retains
per-revision results. macOS is supported on a best-effort basis, and CI
coverage for it is highly limited.

## Documentation

Expand Down
3 changes: 2 additions & 1 deletion gems/libtmux-mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,8 @@ pass the invitation to [`accept_shell`][mcp-application-accept_shell].
and says to upgrade tmux and restart the server.
- **Linux, including WSL, and macOS.** The core
[compatibility workflow][compat] runs Ruby 3.3, 3.4 and 4.0 with tmux 3.3a
through 3.8 on Ubuntu 24.04 and macOS 15.
through 3.8 on Ubuntu 24.04. macOS is supported on a best-effort basis, and
CI coverage for it is highly limited.

## Documentation

Expand Down
3 changes: 2 additions & 1 deletion gems/libtmux-workspace/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,8 @@ values by design.
`error.kind` is `tmux_unsupported`.
- **Linux, including WSL, and macOS.** The library and the command share the
core [compatibility workflow][compat]: Ruby 3.3, 3.4 and 4.0 with tmux 3.3a
through 3.8 on Ubuntu 24.04 and macOS 15, with per-revision results.
through 3.8 on Ubuntu 24.04, with per-revision results. macOS is supported on
a best-effort basis, and CI coverage for it is highly limited.
- **History limit.** On tmux 3.3a to 3.6 the reused initial pane keeps the
global `history-limit`. Set the server's global value before you apply to
get one history size.
Expand Down
5 changes: 3 additions & 2 deletions gems/libtmux/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -732,8 +732,9 @@ server and lists every option.
[server handle][server] checks the connected daemon's release before it sends
a command, and refuses an older daemon even when its client is newer.
- **Linux, including WSL, and macOS.** The [compatibility workflow][compat]
runs Ruby 3.3, 3.4 and 4.0 with tmux 3.3a through 3.8 on Ubuntu 24.04 and
macOS 15.
runs Ruby 3.3, 3.4 and 4.0 with tmux 3.3a through 3.8 on Ubuntu 24.04.
macOS is supported on a best-effort basis, and CI coverage for it is highly
limited.
- **tmux master and old daemons.** On Ubuntu the workflow also runs the suite
against a pinned tmux master, and checks that tmux 3.0a, 3.1c, 3.2a and 3.3
daemons are refused.
Expand Down
4 changes: 2 additions & 2 deletions scripts/matrix
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require "open3"
module CompatibilityMatrix
RUBIES = %w[3.3.12 3.4.10 4.0.7].freeze
TMUXES = %w[3.3a 3.4 3.5a 3.6 3.7c 3.8].freeze
SYSTEMS = %w[linux macos].freeze
SYSTEMS = %w[linux].freeze
ROOT = File.expand_path("..", __dir__)

def self.cells
Expand All @@ -34,7 +34,7 @@ module CompatibilityMatrix
end

def self.execute(cell, rubies, tmuxes, directory)
host = RUBY_PLATFORM.include?("linux") ? "linux" : RUBY_PLATFORM.include?("darwin") ? "macos" : "unsupported"
host = RUBY_PLATFORM.include?("linux") ? "linux" : "unsupported"
return cell.merge("status" => "MISSING_RUNNER") unless host == cell.fetch("os")

ruby, tmux = rubies[cell.fetch("ruby")], tmuxes[cell.fetch("tmux")]
Expand Down
13 changes: 13 additions & 0 deletions test/unit/compatibility_workflow_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,17 @@ def test_supported_cells_and_the_development_build_name_their_lane
assert_equal "supported", WORKFLOW.fetch("jobs").fetch(name).fetch("env").fetch("LIBTMUX_VERSION_CHECK_EXPECT"), name
end
end

def test_no_job_runs_on_macos
runners = WORKFLOW.fetch("jobs").flat_map do |_name, job|
[job.fetch("runs-on"), *job.dig("strategy", "matrix", "platform")&.map { |platform| platform.fetch("runner") }]
end
refute_empty runners
runners.each { |runner| refute_match(/macos/i, runner.to_s) }
assert_equal ["linux"], CompatibilityWorkflowTest.platform_systems
end

def self.platform_systems
WORKFLOW.dig("jobs", "cell", "strategy", "matrix", "platform").map { |platform| platform.fetch("system") }
end
end
5 changes: 3 additions & 2 deletions test/unit/matrix_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def test_plan_preserves_all_required_cells_and_cannot_claim_missing_cells_pass
assert_equal "PARTIAL", report.fetch("status")
assert report.fetch("cells").all? { |cell| cell.fetch("status") == "UNVERIFIED" }
assert_equal %w[3.3a 3.4 3.5a 3.6 3.7c 3.8], report.fetch("cells").map { |cell| cell.fetch("tmux") }.uniq
assert_equal ["linux"], report.fetch("cells").map { |cell| cell.fetch("os") }.uniq
assert_equal ["positive_native_identity"], report.fetch("cells").map { |cell| cell["process_bound_mcp"] }.uniq
output, _, status = Open3.capture3(Gem.ruby, path, "--require-all")
refute status.success?
Expand Down Expand Up @@ -83,8 +84,8 @@ def test_failed_identity_probe_cannot_dispatch_the_suite
File.write(ruby, "#!/bin/sh\nif [ \"$1\" = --disable=gems ]; then printf 4.0.7; else touch '#{marker}'; exit 7; fi\n")
File.write(tmux, "#!/bin/sh\nprintf 'tmux 3.7c\\n'\nexit 1\n")
[ruby, tmux].each { |path| File.chmod(0o700, path) }
os = RUBY_PLATFORM.include?("darwin") ? "macos" : "linux"
cell = CompatibilityMatrix.cells.find { |item| item.fetch("id") == "#{os}/4.0.7/3.7c" }
skip "the matrix runs on Linux only" unless RUBY_PLATFORM.include?("linux")
cell = CompatibilityMatrix.cells.find { |item| item.fetch("id") == "linux/4.0.7/3.7c" }
result = CompatibilityMatrix.execute(cell, {"4.0.7" => ruby}, {"3.7c" => tmux}, directory)
assert_equal "WRONG_TOOLCHAIN", result.fetch("status")
refute File.exist?(marker)
Expand Down
Loading