mirror of
https://github.com/openai/codex.git
synced 2026-11-05 20:10:33 +00:00
Run Bazel CI locally without BuildBuddy credentials (#59055)
## What changed - Remove automatic BuildBuddy configuration and credential forwarding from Bazel CI, release, SDK, and voice builds. Strip remote execution CI configs in the shared wrapper while retaining explicit remote configurations for local use. - Use native Windows host tools and audio dependencies for Windows Bazel actions, forwarding the required toolchain and environment settings. - Initialize message-board MCP servers through a per-session `OnceCell` so server startup does not hold the shared registry lock across an await. - Expose the message-board test helper to the core Bazel package and update the runtime-auth test call for the `reauth` argument. GitOrigin-RevId: 5d5c1f4d71fa841090dea8eec8006380981fb65b
This commit is contained in:
committed by
copyberry
parent
fbf5f0d3a7
commit
3f958ac2fe
@@ -5,10 +5,6 @@ inputs:
|
||||
target:
|
||||
description: Runner target passed to prepare-bazel-ci.
|
||||
required: true
|
||||
buildbuddy-api-key:
|
||||
description: BuildBuddy API key used by Bazel CI.
|
||||
required: false
|
||||
default: ""
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
@@ -19,19 +15,19 @@ runs:
|
||||
cache-scope: bazel-argument-comment-lint
|
||||
|
||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
if: ${{ runner.os == 'Windows' && inputs.buildbuddy-api-key == '' }}
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
with:
|
||||
python-version: "3.12"
|
||||
architecture: x64
|
||||
|
||||
- name: Prepare native Windows audio dependencies
|
||||
if: ${{ runner.os == 'Windows' && inputs.buildbuddy-api-key == '' }}
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
uses: ./third_party/voice/cargo-ci/windows-setup
|
||||
with:
|
||||
target: x86_64-pc-windows-msvc
|
||||
|
||||
- name: Verify native Windows audio dependencies
|
||||
if: ${{ runner.os == 'Windows' && inputs.buildbuddy-api-key == '' }}
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
shell: bash
|
||||
run: |
|
||||
: "${VOICE_WINDOWS_BAZEL_REPOSITORY:?Windows voice tools are required}"
|
||||
@@ -56,8 +52,6 @@ runs:
|
||||
|
||||
- name: Run argument comment lint on codex-rs via Bazel
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ inputs.buildbuddy-api-key }}
|
||||
shell: bash
|
||||
run: |
|
||||
bazel_targets="$(./tools/argument-comment-lint/list-bazel-targets.sh)"
|
||||
@@ -72,8 +66,6 @@ runs:
|
||||
|
||||
- name: Run argument comment lint on codex-rs via Bazel
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ inputs.buildbuddy-api-key }}
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/scripts/run-argument-comment-lint-bazel.sh \
|
||||
|
||||
@@ -9,7 +9,7 @@ if [[ "${RUNNER_OS:-}" == "Windows" ]]; then
|
||||
# lint aspect can run across the compatible crate graph instead of failing the
|
||||
# whole build after analysis.
|
||||
bazel_lint_args+=("--skip_incompatible_explicit_targets")
|
||||
if [[ -z "${BUILDBUDDY_API_KEY:-}" && -n "${VOICE_WINDOWS_BAZEL_REPOSITORY:-}" ]]; then
|
||||
if [[ -n "${VOICE_WINDOWS_BAZEL_REPOSITORY:-}" ]]; then
|
||||
: "${VOICE_WINDOWS_BAZEL_REPOSITORY:?Windows voice tools are required}"
|
||||
: "${VOICE_WINDOWS_SYSTEM_ROOT:?Windows SystemRoot is required}"
|
||||
: "${VOICE_WINDOWS_HOST_ARCH:?Windows host architecture is required}"
|
||||
|
||||
@@ -69,32 +69,11 @@ run_bazel_with_startup_args() {
|
||||
run_bazel "$@"
|
||||
}
|
||||
|
||||
ci_config=ci-linux
|
||||
case "${RUNNER_OS:-}" in
|
||||
macOS)
|
||||
ci_config=ci-macos
|
||||
;;
|
||||
Windows)
|
||||
if [[ $windows_cross_compile -eq 1 ]]; then
|
||||
ci_config=ci-windows-cross
|
||||
else
|
||||
ci_config=ci-windows
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
print_bazel_test_log_tails() {
|
||||
local console_log="$1"
|
||||
local testlogs_dir
|
||||
|
||||
local -a bazel_info_args=(info)
|
||||
if [[ -n "${BUILDBUDDY_API_KEY:-}" ]]; then
|
||||
# `bazel info` needs the same CI config as the failed test invocation so
|
||||
# platform-specific output roots match. On Windows, omitting `ci-windows`
|
||||
# would point at `local_windows-fastbuild` even when the test ran with the
|
||||
# MSVC host platform under `local_windows_msvc-fastbuild`.
|
||||
bazel_info_args+=("--config=${ci_config}")
|
||||
fi
|
||||
|
||||
# Only pass flags that affect Bazel's output-root selection or repository
|
||||
# lookup. Test/build-only flags such as execution logs or remote download
|
||||
@@ -255,10 +234,8 @@ if [[ ${#bazel_args[@]} -eq 0 || ${#bazel_targets[@]} -eq 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${RUNNER_OS:-}" == "Windows" && $windows_cross_compile -eq 1 && -z "${BUILDBUDDY_API_KEY:-}" ]]; then
|
||||
# Windows cross-compilation depends on authenticated RBE. Preserve the local
|
||||
# Windows build shape when credentials are unavailable.
|
||||
ci_config=ci-windows
|
||||
if [[ "${RUNNER_OS:-}" == "Windows" && $windows_cross_compile -eq 1 ]]; then
|
||||
# Run Windows actions with the native MSVC host platform.
|
||||
windows_msvc_host_platform=1
|
||||
fi
|
||||
|
||||
@@ -287,22 +264,9 @@ if [[ $remote_download_toplevel -eq 1 ]]; then
|
||||
post_config_bazel_args+=(--remote_download_toplevel)
|
||||
fi
|
||||
|
||||
if [[ "${RUNNER_OS:-}" == "Windows" && $windows_cross_compile -eq 1 && -n "${BUILDBUDDY_API_KEY:-}" ]]; then
|
||||
# `--enable_platform_specific_config` expands `common:windows` on Windows
|
||||
# hosts after ordinary rc configs, which can override `ci-windows-cross`'s
|
||||
# RBE host platform. Repeat the host platform on the command line so V8 and
|
||||
# other genrules execute on Linux RBE workers instead of Git Bash locally.
|
||||
#
|
||||
# Bazel also derives the default genrule shell from the client host. Without
|
||||
# an explicit shell executable, remote Linux actions can be asked to run
|
||||
# `C:\Program Files\Git\usr\bin\bash.exe`.
|
||||
post_config_bazel_args+=(--host_platform=//:rbe --shell_executable=/bin/bash)
|
||||
fi
|
||||
|
||||
if [[ "${RUNNER_OS:-}" == "Windows" && $windows_cross_compile -eq 1 && -z "${BUILDBUDDY_API_KEY:-}" ]]; then
|
||||
# The Windows cross-compile config depends on authenticated remote
|
||||
# execution. When credentials are unavailable, keep the local build shape
|
||||
# and its lower concurrency cap.
|
||||
if [[ "${RUNNER_OS:-}" == "Windows" && $windows_cross_compile -eq 1 ]]; then
|
||||
# Bound concurrent native Windows actions to fit the runner.
|
||||
post_config_bazel_args+=(--jobs=8)
|
||||
fi
|
||||
|
||||
@@ -324,35 +288,49 @@ if [[ -n "${CODEX_BAZEL_EXECUTION_LOG_COMPACT_DIR:-}" ]]; then
|
||||
fi
|
||||
|
||||
if [[ "${RUNNER_OS:-}" == "Windows" ]]; then
|
||||
pass_windows_build_env=1
|
||||
if [[ $windows_cross_compile -eq 1 && -n "${BUILDBUDDY_API_KEY:-}" ]]; then
|
||||
# Remote build actions execute on Linux RBE workers. Passing the Windows
|
||||
# runner's build environment there makes Bazel genrules try to execute
|
||||
# C:\Program Files\Git\usr\bin\bash.exe on Linux.
|
||||
pass_windows_build_env=0
|
||||
fi
|
||||
|
||||
if [[ $pass_windows_build_env -eq 1 ]]; then
|
||||
windows_action_env_vars=(
|
||||
INCLUDE
|
||||
LIB
|
||||
LIBPATH
|
||||
UCRTVersion
|
||||
UniversalCRTSdkDir
|
||||
VCINSTALLDIR
|
||||
VCToolsInstallDir
|
||||
WindowsLibPath
|
||||
WindowsSdkBinPath
|
||||
WindowsSdkDir
|
||||
WindowsSDKLibVersion
|
||||
WindowsSDKVersion
|
||||
windows_action_env_vars=(
|
||||
INCLUDE
|
||||
LIB
|
||||
LIBPATH
|
||||
UCRTVersion
|
||||
UniversalCRTSdkDir
|
||||
VCINSTALLDIR
|
||||
VCToolsInstallDir
|
||||
WindowsLibPath
|
||||
WindowsSdkBinPath
|
||||
WindowsSdkDir
|
||||
WindowsSDKLibVersion
|
||||
WindowsSDKVersion
|
||||
)
|
||||
|
||||
for env_var in "${windows_action_env_vars[@]}"; do
|
||||
if [[ -n "${!env_var:-}" ]]; then
|
||||
post_config_bazel_args+=("--action_env=${env_var}" "--host_action_env=${env_var}")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -n "${VOICE_WINDOWS_BAZEL_REPOSITORY:-}" ]]; then
|
||||
# Reuse the verified native audio inputs for local CI's voice targets.
|
||||
# These fixed values must be visible during Starlark analysis as well
|
||||
# as action execution; inherited --action_env values are insufficient.
|
||||
: "${VOICE_WINDOWS_SYSTEM_ROOT:?Windows SystemRoot is required}"
|
||||
: "${VOICE_WINDOWS_HOST_ARCH:?Windows host architecture is required}"
|
||||
# GNU-host lint jobs still need the LLVM linker for their build tools.
|
||||
if [[ $windows_msvc_host_platform -eq 1 ]]; then
|
||||
post_config_bazel_args+=("--config=ci-windows-msvc")
|
||||
fi
|
||||
post_config_bazel_args+=(
|
||||
"--workspace_status_command=./scripts/workspace-status.cmd"
|
||||
"--extra_toolchains=//third_party/voice:windows_pkg_config_toolchain,//third_party/voice:windows_cmake_toolchain"
|
||||
"--repo_env=BAZEL_MSVC_RUNTIME_VISUAL_STUDIO_EULA=1"
|
||||
"--inject_repository=voice_windows_tools=${VOICE_WINDOWS_BAZEL_REPOSITORY}"
|
||||
"--//third_party/voice:windows_installed_tools=@voice_windows_tools//:tools"
|
||||
"--action_env=SystemRoot=${VOICE_WINDOWS_SYSTEM_ROOT}"
|
||||
"--host_action_env=SystemRoot=${VOICE_WINDOWS_SYSTEM_ROOT}"
|
||||
"--action_env=PROCESSOR_ARCHITECTURE=${VOICE_WINDOWS_HOST_ARCH}"
|
||||
"--host_action_env=PROCESSOR_ARCHITECTURE=${VOICE_WINDOWS_HOST_ARCH}"
|
||||
)
|
||||
|
||||
for env_var in "${windows_action_env_vars[@]}"; do
|
||||
if [[ -n "${!env_var:-}" ]]; then
|
||||
post_config_bazel_args+=("--action_env=${env_var}" "--host_action_env=${env_var}")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ -z "${CODEX_BAZEL_WINDOWS_PATH:-}" ]]; then
|
||||
@@ -360,20 +338,10 @@ if [[ "${RUNNER_OS:-}" == "Windows" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $pass_windows_build_env -eq 1 ]]; then
|
||||
post_config_bazel_args+=(
|
||||
"--action_env=PATH=${CODEX_BAZEL_WINDOWS_PATH}"
|
||||
"--host_action_env=PATH=${CODEX_BAZEL_WINDOWS_PATH}"
|
||||
)
|
||||
elif [[ $windows_cross_compile -eq 1 ]]; then
|
||||
# Remote build actions run on Linux RBE workers. Give their shell snippets
|
||||
# a Linux PATH while preserving CODEX_BAZEL_WINDOWS_PATH below for local
|
||||
# Windows test execution.
|
||||
post_config_bazel_args+=(
|
||||
"--action_env=PATH=/usr/bin:/bin"
|
||||
"--host_action_env=PATH=/usr/bin:/bin"
|
||||
)
|
||||
fi
|
||||
post_config_bazel_args+=(
|
||||
"--action_env=PATH=${CODEX_BAZEL_WINDOWS_PATH}"
|
||||
"--host_action_env=PATH=${CODEX_BAZEL_WINDOWS_PATH}"
|
||||
)
|
||||
post_config_bazel_args+=("--test_env=PATH=${CODEX_BAZEL_WINDOWS_PATH}")
|
||||
fi
|
||||
|
||||
@@ -383,14 +351,8 @@ trap 'rm -f "$bazel_console_log"' EXIT
|
||||
bazel_run_args=(
|
||||
"${bazel_args[@]}"
|
||||
)
|
||||
if [[ -n "${BUILDBUDDY_API_KEY:-}" ]]; then
|
||||
echo "BuildBuddy API key is available; using remote Bazel configuration."
|
||||
bazel_run_args+=("--config=${ci_config}")
|
||||
else
|
||||
echo "BuildBuddy API key is not available; using local Bazel configuration."
|
||||
if [[ "${bazel_args[0]}" == "test" ]]; then
|
||||
bazel_run_args+=("--test_env=INSTA_UPDATE=no")
|
||||
fi
|
||||
if [[ "${bazel_args[0]}" == "test" ]]; then
|
||||
bazel_run_args+=("--test_env=INSTA_UPDATE=no")
|
||||
fi
|
||||
if (( ${#post_config_bazel_args[@]} > 0 )); then
|
||||
bazel_run_args+=("${post_config_bazel_args[@]}")
|
||||
@@ -399,7 +361,7 @@ set +e
|
||||
# Work around Bazel 9 remote repo contents cache / overlay materialization
|
||||
# failures seen in CI (for example "is not a symlink" or permission errors
|
||||
# while materializing external repos such as rules_perl). This only disables
|
||||
# the startup-level repo contents cache; keyed runs still use BuildBuddy.
|
||||
# the startup-level repo contents cache.
|
||||
run_bazel_with_startup_args \
|
||||
--noexperimental_remote_repo_contents_cache \
|
||||
"${bazel_run_args[@]}" \
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from collections.abc import Mapping
|
||||
from collections.abc import Sequence
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
OPENAI_REPOSITORY = "openai/codex"
|
||||
# Remote configurations select cache/BES/download endpoints. Their -rbe forms
|
||||
# also select the matching remote executor endpoint.
|
||||
GENERIC_REMOTE_CONFIG = "buildbuddy-generic"
|
||||
OPENAI_REMOTE_CONFIG = "buildbuddy-openai"
|
||||
# These CI configurations require remote build execution. The wrapper supplies
|
||||
# an RBE configuration, which also includes the common `remote` settings.
|
||||
# These configs select remote execution, which is unavailable on CI runners.
|
||||
REMOTE_EXECUTION_CONFIGS = {
|
||||
"--config=ci-linux",
|
||||
"--config=ci-macos",
|
||||
@@ -56,68 +48,13 @@ def startup_args(args: Sequence[str], env: Mapping[str, str]) -> list[str]:
|
||||
for arg in configured_startup_args
|
||||
):
|
||||
# Work around Bazel 9 overlay materialization failures seen in CI. This
|
||||
# disables only the startup-level repo contents cache; keyed runs still
|
||||
# use BuildBuddy.
|
||||
# disables only the startup-level repo contents cache.
|
||||
injected_args.append("--noexperimental_remote_repo_contents_cache")
|
||||
|
||||
return injected_args
|
||||
|
||||
|
||||
# Only authenticated workflow runs executing trusted upstream code may use the
|
||||
# OpenAI BuildBuddy host. A pull request event without proof that its head is
|
||||
# in the upstream repository fails closed to the generic host.
|
||||
def is_trusted_upstream_run(env: Mapping[str, str]) -> bool:
|
||||
# `GITHUB_REPOSITORY` is easy to set locally. Requiring GitHub's workflow
|
||||
# marker prevents a local command from opting itself into the OpenAI host.
|
||||
if (
|
||||
env.get("GITHUB_ACTIONS") != "true"
|
||||
or env.get("GITHUB_REPOSITORY") != OPENAI_REPOSITORY
|
||||
):
|
||||
return False
|
||||
# Non-PR workflow runs in `openai/codex` execute upstream refs, so they are
|
||||
# trusted. Fork code reaches these workflows only through pull requests.
|
||||
if env.get("GITHUB_EVENT_NAME") != "pull_request":
|
||||
return True
|
||||
|
||||
event_path = env.get("GITHUB_EVENT_PATH")
|
||||
if not event_path:
|
||||
return False
|
||||
try:
|
||||
event = json.loads(Path(event_path).read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError):
|
||||
return False
|
||||
|
||||
try:
|
||||
return event["pull_request"]["head"]["repo"]["fork"] is False
|
||||
except (KeyError, TypeError):
|
||||
return False
|
||||
|
||||
|
||||
def uses_openai_host(env: Mapping[str, str]) -> bool:
|
||||
return bool(env.get("BUILDBUDDY_API_KEY")) and is_trusted_upstream_run(env)
|
||||
|
||||
|
||||
def uses_remote_execution(args: Sequence[str]) -> bool:
|
||||
try:
|
||||
separator_idx = args.index("--")
|
||||
except ValueError:
|
||||
separator_idx = len(args)
|
||||
return any(arg in REMOTE_EXECUTION_CONFIGS for arg in args[:separator_idx])
|
||||
|
||||
|
||||
def remote_config(args: Sequence[str], env: Mapping[str, str]) -> str | None:
|
||||
if not env.get("BUILDBUDDY_API_KEY"):
|
||||
return None
|
||||
|
||||
config = OPENAI_REMOTE_CONFIG if uses_openai_host(env) else GENERIC_REMOTE_CONFIG
|
||||
if uses_remote_execution(args):
|
||||
config += "-rbe"
|
||||
return config
|
||||
|
||||
|
||||
def bazel_args_without_remote_execution(args: Sequence[str]) -> list[str]:
|
||||
# Remote CI configs require BuildBuddy credentials. Removing them preserves
|
||||
# the local fallback used for fork pull requests.
|
||||
try:
|
||||
separator_idx = args.index("--")
|
||||
except ValueError:
|
||||
@@ -138,26 +75,7 @@ def bazel_args_with_remote_config(
|
||||
if command_idx is None:
|
||||
raise ValueError("expected a Bazel command")
|
||||
|
||||
config = remote_config(args, env)
|
||||
if config is None:
|
||||
configured_args = bazel_args_without_remote_execution(args)
|
||||
else:
|
||||
# `remote_config()` returns a configuration only when this key is present.
|
||||
api_key = env["BUILDBUDDY_API_KEY"]
|
||||
remote_args = [
|
||||
f"--config={config}",
|
||||
f"--remote_header=x-buildbuddy-api-key={api_key}",
|
||||
]
|
||||
|
||||
# Insert immediately after the Bazel command. This keeps wrapper-added
|
||||
# options out of positional payloads and lets later CI configs override
|
||||
# shared RBE defaults such as the Windows cross-compilation exec platforms.
|
||||
configured_args = [
|
||||
*args[: command_idx + 1],
|
||||
*remote_args,
|
||||
*args[command_idx + 1 :],
|
||||
]
|
||||
|
||||
configured_args = bazel_args_without_remote_execution(args)
|
||||
try:
|
||||
separator_idx = configured_args.index("--")
|
||||
except ValueError:
|
||||
@@ -188,21 +106,6 @@ def bazel_command(*args: str, env: Mapping[str, str] | None = None) -> list[str]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
config = remote_config(sys.argv[1:], os.environ)
|
||||
if config is None:
|
||||
print(
|
||||
"BuildBuddy key unavailable; using local Bazel configuration.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
else:
|
||||
host_description = (
|
||||
"OpenAI tenant" if uses_openai_host(os.environ) else "generic"
|
||||
)
|
||||
print(
|
||||
f"Using {host_description} BuildBuddy configuration: {config}.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
|
||||
command = bazel_command(*sys.argv[1:])
|
||||
if os.name == "nt":
|
||||
# Windows CRT exec can split arguments containing spaces and lose the
|
||||
|
||||
@@ -1,177 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
import run_bazel_with_buildbuddy
|
||||
|
||||
|
||||
class RunBazelWithBuildBuddyTest(unittest.TestCase):
|
||||
def github_env(
|
||||
self,
|
||||
temp_dir: str,
|
||||
*,
|
||||
repository: str = "openai/codex",
|
||||
fork: bool = False,
|
||||
event_name: str = "pull_request",
|
||||
) -> dict[str, str]:
|
||||
event_path = Path(temp_dir) / "event.json"
|
||||
event_path.write_text(
|
||||
json.dumps({"pull_request": {"head": {"repo": {"fork": fork}}}}),
|
||||
encoding="utf-8",
|
||||
)
|
||||
return {
|
||||
"BUILDBUDDY_API_KEY": "token",
|
||||
"GITHUB_ACTIONS": "true",
|
||||
"GITHUB_EVENT_NAME": event_name,
|
||||
"GITHUB_EVENT_PATH": str(event_path),
|
||||
"GITHUB_REPOSITORY": repository,
|
||||
}
|
||||
|
||||
def test_keyless_invocation_drops_remote_ci_configuration(self) -> None:
|
||||
self.assertIsNone(
|
||||
run_bazel_with_buildbuddy.remote_config(
|
||||
["build", "--config=ci-linux", "//codex-rs/cli:codex"],
|
||||
{},
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
run_bazel_with_buildbuddy.bazel_args_with_remote_config(
|
||||
["build", "--config=ci-linux", "--", "//codex-rs/cli:codex"],
|
||||
{},
|
||||
),
|
||||
["build", "--", "//codex-rs/cli:codex"],
|
||||
)
|
||||
|
||||
def test_program_arguments_after_separator_do_not_select_or_lose_rbe(self) -> None:
|
||||
args = ["run", "//codex-rs/cli:codex", "--", "--config=remote"]
|
||||
|
||||
self.assertEqual(
|
||||
run_bazel_with_buildbuddy.bazel_args_with_remote_config(args, {}),
|
||||
args,
|
||||
)
|
||||
self.assertEqual(
|
||||
run_bazel_with_buildbuddy.remote_config(
|
||||
args, {"BUILDBUDDY_API_KEY": "fork-token"}
|
||||
),
|
||||
"buildbuddy-generic",
|
||||
)
|
||||
|
||||
def test_upstream_push_selects_openai_rbe_before_target_separator(self) -> None:
|
||||
with TemporaryDirectory() as temp_dir:
|
||||
env = self.github_env(temp_dir, event_name="push")
|
||||
|
||||
self.assertEqual(
|
||||
run_bazel_with_buildbuddy.bazel_args_with_remote_config(
|
||||
["build", "--config=ci-linux", "--", "//codex-rs/cli:codex"],
|
||||
env,
|
||||
),
|
||||
[
|
||||
"build",
|
||||
"--config=buildbuddy-openai-rbe",
|
||||
"--remote_header=x-buildbuddy-api-key=token",
|
||||
"--config=ci-linux",
|
||||
"--",
|
||||
"//codex-rs/cli:codex",
|
||||
],
|
||||
)
|
||||
|
||||
def test_windows_cross_ci_configuration_follows_remote_configuration(self) -> None:
|
||||
env = {"BUILDBUDDY_API_KEY": "fork-token"}
|
||||
|
||||
self.assertEqual(
|
||||
run_bazel_with_buildbuddy.bazel_args_with_remote_config(
|
||||
["build", "--config=ci-windows-cross", "//codex-rs/cli:codex"],
|
||||
env,
|
||||
),
|
||||
[
|
||||
"build",
|
||||
"--config=buildbuddy-generic-rbe",
|
||||
"--remote_header=x-buildbuddy-api-key=fork-token",
|
||||
"--config=ci-windows-cross",
|
||||
"//codex-rs/cli:codex",
|
||||
],
|
||||
)
|
||||
|
||||
def test_query_remote_configuration_is_inserted_before_expression(self) -> None:
|
||||
expression = 'kind("rust_library rule", //codex-rs/...)'
|
||||
env = {"BUILDBUDDY_API_KEY": "fork-token"}
|
||||
|
||||
for command in ("query", "cquery", "aquery"):
|
||||
with self.subTest(command=command):
|
||||
self.assertEqual(
|
||||
run_bazel_with_buildbuddy.bazel_args_with_remote_config(
|
||||
[
|
||||
command,
|
||||
"--config=ci-windows-cross",
|
||||
"--output=label",
|
||||
expression,
|
||||
],
|
||||
env,
|
||||
),
|
||||
[
|
||||
command,
|
||||
"--config=buildbuddy-generic-rbe",
|
||||
"--remote_header=x-buildbuddy-api-key=fork-token",
|
||||
"--config=ci-windows-cross",
|
||||
"--output=label",
|
||||
expression,
|
||||
],
|
||||
)
|
||||
|
||||
def test_same_repository_pull_request_selects_openai_host(self) -> None:
|
||||
with TemporaryDirectory() as temp_dir:
|
||||
self.assertEqual(
|
||||
run_bazel_with_buildbuddy.remote_config(
|
||||
["build", "--config=ci-v8"], self.github_env(temp_dir)
|
||||
),
|
||||
"buildbuddy-openai-rbe",
|
||||
)
|
||||
|
||||
def test_fork_pull_request_cannot_select_openai_host(self) -> None:
|
||||
with TemporaryDirectory() as temp_dir:
|
||||
env = self.github_env(temp_dir, fork=True)
|
||||
|
||||
self.assertEqual(
|
||||
run_bazel_with_buildbuddy.remote_config(
|
||||
["build", "--config=ci-v8"], env
|
||||
),
|
||||
"buildbuddy-generic-rbe",
|
||||
)
|
||||
|
||||
def test_run_in_fork_repository_cannot_select_openai_host(self) -> None:
|
||||
with TemporaryDirectory() as temp_dir:
|
||||
env = self.github_env(temp_dir, repository="contributor/codex")
|
||||
|
||||
self.assertEqual(
|
||||
run_bazel_with_buildbuddy.remote_config(
|
||||
["build", "--config=ci-v8"], env
|
||||
),
|
||||
"buildbuddy-generic-rbe",
|
||||
)
|
||||
|
||||
def test_pull_request_without_readable_event_payload_fails_closed(self) -> None:
|
||||
for event_path in (None, "missing-event.json"):
|
||||
env = {
|
||||
"BUILDBUDDY_API_KEY": "token",
|
||||
"GITHUB_ACTIONS": "true",
|
||||
"GITHUB_EVENT_NAME": "pull_request",
|
||||
"GITHUB_REPOSITORY": "openai/codex",
|
||||
}
|
||||
if event_path is not None:
|
||||
env["GITHUB_EVENT_PATH"] = event_path
|
||||
|
||||
with self.subTest(event_path=event_path):
|
||||
self.assertEqual(
|
||||
run_bazel_with_buildbuddy.remote_config(["build"], env),
|
||||
"buildbuddy-generic",
|
||||
)
|
||||
|
||||
def test_bazel_command_uses_configured_binary_locally(self) -> None:
|
||||
self.assertEqual(
|
||||
run_bazel_with_buildbuddy.bazel_command(
|
||||
@@ -266,7 +104,6 @@ class RunBazelWithBuildBuddyTest(unittest.TestCase):
|
||||
env = os.environ.copy()
|
||||
env["CODEX_BAZEL_BIN"] = sys.executable
|
||||
env.pop("BAZEL_OUTPUT_USER_ROOT", None)
|
||||
env.pop("BUILDBUDDY_API_KEY", None)
|
||||
env.pop("GITHUB_ACTIONS", None)
|
||||
|
||||
result = subprocess.run(
|
||||
|
||||
@@ -72,7 +72,7 @@ class RustyV8BazelTest(unittest.TestCase):
|
||||
with patch.object(rusty_v8_bazel, "MODULE_BAZEL", module_bazel):
|
||||
self.assertEqual("146.4.0", rusty_v8_bazel.command_version(None))
|
||||
|
||||
def test_bazel_commands_use_shared_buildbuddy_remote_config_library(self) -> None:
|
||||
def test_bazel_commands_use_shared_ci_options(self) -> None:
|
||||
with patch.dict(environ, {}, clear=True):
|
||||
self.assertEqual(
|
||||
[
|
||||
@@ -86,22 +86,6 @@ class RustyV8BazelTest(unittest.TestCase):
|
||||
"//third_party/v8:release",
|
||||
),
|
||||
)
|
||||
with patch.dict(environ, {"BUILDBUDDY_API_KEY": "token"}, clear=True):
|
||||
self.assertEqual(
|
||||
[
|
||||
"bazel",
|
||||
"build",
|
||||
"--config=buildbuddy-generic-rbe",
|
||||
"--remote_header=x-buildbuddy-api-key=token",
|
||||
"--config=ci-v8",
|
||||
"//third_party/v8:release",
|
||||
],
|
||||
rusty_v8_bazel.bazel_command(
|
||||
"build",
|
||||
"--config=ci-v8",
|
||||
"//third_party/v8:release",
|
||||
),
|
||||
)
|
||||
|
||||
def test_release_pair_labels_and_staged_names_distinguish_sandbox_artifacts(
|
||||
self,
|
||||
|
||||
+29
-36
@@ -17,9 +17,7 @@ jobs:
|
||||
test:
|
||||
# PRs use the sharded Windows cross-compiled test jobs below. Post-merge
|
||||
# pushes to main also run the native Windows test job for broader Windows
|
||||
# signal without putting PR latency back on the critical path. When
|
||||
# Code-mode unit tests run on every Bazel target. When authenticated RBE
|
||||
# is available, the Windows-cross shards exercise the source-built V8 path.
|
||||
# signal without putting PR latency back on the critical path.
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -72,8 +70,6 @@ jobs:
|
||||
|
||||
- name: Check MODULE.bazel.lock is up to date
|
||||
if: matrix.os == 'ubuntu-24.04' && matrix.target == 'x86_64-unknown-linux-gnu'
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
shell: bash
|
||||
run: ./scripts/check-module-bazel-lock.sh
|
||||
|
||||
@@ -86,8 +82,6 @@ jobs:
|
||||
echo "CODEX_COMPAT_RELEASES=$releases" >> "$GITHUB_ENV"
|
||||
|
||||
- name: bazel test //...
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
shell: bash
|
||||
run: |
|
||||
bazel_targets=(
|
||||
@@ -139,9 +133,7 @@ jobs:
|
||||
uses: ./.github/actions/check-clean-worktree
|
||||
|
||||
test-windows-shard:
|
||||
# Split the Windows Bazel test leg across separate Windows hosts. Jobs with
|
||||
# BuildBuddy credentials use Linux RBE for build actions; test execution
|
||||
# remains on a Windows runner.
|
||||
# Build and test Windows shards on separate Windows runners.
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -164,7 +156,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Test BuildBuddy Bazel wrapper
|
||||
- name: Test Bazel command wrapper
|
||||
if: matrix.shard == 1
|
||||
shell: pwsh
|
||||
run: python .github/scripts/test_run_bazel_with_buildbuddy.py
|
||||
@@ -184,11 +176,16 @@ jobs:
|
||||
# the PR-blocking critical path after the useful test work is done.
|
||||
cache-scope: bazel-test
|
||||
|
||||
- name: Prepare native Windows audio dependencies
|
||||
if: runner.os == 'Windows'
|
||||
uses: ./third_party/voice/cargo-ci/windows-setup
|
||||
with:
|
||||
target: x86_64-pc-windows-msvc
|
||||
|
||||
- name: bazel test shard
|
||||
env:
|
||||
BAZEL_TEST_SHARD: ${{ matrix.shard }}
|
||||
BAZEL_TEST_SHARD_COUNT: 4
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -283,9 +280,13 @@ jobs:
|
||||
target: x86_64-pc-windows-msvc
|
||||
cache-scope: bazel-${{ github.job }}
|
||||
|
||||
- name: Prepare native Windows audio dependencies
|
||||
if: runner.os == 'Windows'
|
||||
uses: ./third_party/voice/cargo-ci/windows-setup
|
||||
with:
|
||||
target: x86_64-pc-windows-msvc
|
||||
|
||||
- name: bazel test //...
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
shell: bash
|
||||
run: |
|
||||
bazel_targets=(
|
||||
@@ -376,6 +377,12 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
cache-scope: bazel-${{ github.job }}
|
||||
|
||||
- name: Prepare native Windows audio dependencies
|
||||
if: runner.os == 'Windows'
|
||||
uses: ./third_party/voice/cargo-ci/windows-setup
|
||||
with:
|
||||
target: x86_64-pc-windows-msvc
|
||||
|
||||
- name: Resolve app-server/exec-server compatibility releases
|
||||
if: runner.os == 'Linux'
|
||||
env:
|
||||
@@ -385,8 +392,6 @@ jobs:
|
||||
echo "CODEX_COMPAT_RELEASES=$releases" >> "$GITHUB_ENV"
|
||||
|
||||
- name: bazel build --config=clippy lint targets
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
shell: bash
|
||||
run: |
|
||||
bazel_clippy_args=(
|
||||
@@ -397,19 +402,9 @@ jobs:
|
||||
bazel_wrapper_args=()
|
||||
bazel_target_list_args=()
|
||||
if [[ "${RUNNER_OS}" == "Windows" ]]; then
|
||||
# Keep this aligned with the fast Windows Bazel test job: use
|
||||
# Linux RBE for clippy build actions while targeting Windows
|
||||
# gnullvm. Fork/community PRs without the BuildBuddy secret fall
|
||||
# back inside `run-bazel-ci.sh` to the previous local Windows MSVC
|
||||
# host-platform shape.
|
||||
bazel_wrapper_args+=(--windows-cross-compile)
|
||||
bazel_target_list_args+=(--windows-cross-compile)
|
||||
if [[ -z "${BUILDBUDDY_API_KEY:-}" ]]; then
|
||||
# The fork fallback can see incompatible explicit Windows-cross
|
||||
# internal test binaries in the generated target list. Preserve
|
||||
# the old local-fallback behavior there.
|
||||
bazel_clippy_args+=(--skip_incompatible_explicit_targets)
|
||||
fi
|
||||
bazel_clippy_args+=(--skip_incompatible_explicit_targets)
|
||||
fi
|
||||
|
||||
bazel_target_lines="$(./scripts/list-bazel-clippy-targets.sh "${bazel_target_list_args[@]}")"
|
||||
@@ -483,6 +478,12 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
cache-scope: bazel-${{ github.job }}
|
||||
|
||||
- name: Prepare native Windows audio dependencies
|
||||
if: runner.os == 'Windows'
|
||||
uses: ./third_party/voice/cargo-ci/windows-setup
|
||||
with:
|
||||
target: x86_64-pc-windows-msvc
|
||||
|
||||
- name: Resolve app-server/exec-server compatibility releases
|
||||
if: runner.os == 'Linux'
|
||||
env:
|
||||
@@ -492,8 +493,6 @@ jobs:
|
||||
echo "CODEX_COMPAT_RELEASES=$releases" >> "$GITHUB_ENV"
|
||||
|
||||
- name: bazel build verify-release-build targets
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
shell: bash
|
||||
run: |
|
||||
# This job exists to compile Rust code behind
|
||||
@@ -504,11 +503,7 @@ jobs:
|
||||
# Rust debug assertions explicitly.
|
||||
bazel_wrapper_args=()
|
||||
if [[ "${RUNNER_OS}" == "Windows" ]]; then
|
||||
# This is build-only signal, so use the same Linux-RBE
|
||||
# cross-compile path as the fast Windows test and clippy jobs.
|
||||
# Fork/community PRs without the BuildBuddy secret fall back
|
||||
# inside `run-bazel-ci.sh` to the previous local Windows MSVC
|
||||
# host-platform shape.
|
||||
# Use the same native host toolchain as the Windows test shards.
|
||||
bazel_wrapper_args+=(--windows-cross-compile)
|
||||
fi
|
||||
|
||||
@@ -537,8 +532,6 @@ jobs:
|
||||
|
||||
- name: Verify Bazel builds bwrap
|
||||
if: runner.os == 'Linux'
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/scripts/run-bazel-ci.sh \
|
||||
|
||||
@@ -212,7 +212,6 @@ jobs:
|
||||
uses: ./.github/actions/run-argument-comment-lint
|
||||
with:
|
||||
target: ${{ runner.os }}
|
||||
buildbuddy-api-key: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
|
||||
- name: Check for a clean worktree
|
||||
if: always() && !cancelled() && steps.argument_comment_lint_gate.outputs.run == 'true'
|
||||
|
||||
@@ -124,8 +124,6 @@ jobs:
|
||||
- name: Build Bazel release binaries and symbols
|
||||
if: ${{ matrix.build-system == 'bazel' }}
|
||||
uses: ./.github/actions/build-bazel-release
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
bundle: ${{ matrix.bundle }}
|
||||
@@ -253,7 +251,6 @@ jobs:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
VOICE_ARCH: ${{ matrix.arch }}
|
||||
# Use local Bazel while BuildBuddy credentials are unavailable.
|
||||
BUILDBUDDY_API_KEY: ""
|
||||
run: |
|
||||
(cd codex-rs && cargo update --workspace)
|
||||
python .github/scripts/watch_voice_bazel.py "$(cygpath -w "$BASH")" ./.github/scripts/run-bazel-ci.sh \
|
||||
|
||||
@@ -277,8 +277,6 @@ jobs:
|
||||
- name: Build Bazel release binaries and symbols
|
||||
if: ${{ matrix.build-system == 'bazel' }}
|
||||
uses: ./.github/actions/build-bazel-release
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
bundle: ${{ matrix.bundle }}
|
||||
@@ -327,7 +325,6 @@ jobs:
|
||||
env:
|
||||
APP_TARGET: ${{ matrix.target }}
|
||||
# Use local Bazel while BuildBuddy credentials are unavailable.
|
||||
BUILDBUDDY_API_KEY: ""
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
@@ -607,7 +604,6 @@ jobs:
|
||||
TARGET: ${{ matrix.target }}
|
||||
PREFIX: ${{ matrix.prefix }}
|
||||
# Use local Bazel while BuildBuddy credentials are unavailable.
|
||||
BUILDBUDDY_API_KEY: ""
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Release tags bump Cargo.toml without rewriting the workspace lockfile.
|
||||
|
||||
@@ -168,7 +168,6 @@ jobs:
|
||||
|
||||
- name: Build Bazel V8 release pair
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
PLATFORM: ${{ matrix.platform }}
|
||||
SANDBOX: ${{ matrix.sandbox }}
|
||||
TARGET: ${{ matrix.target }}
|
||||
@@ -200,7 +199,6 @@ jobs:
|
||||
- name: Stage release pair
|
||||
env:
|
||||
BAZEL_CONFIG: ${{ matrix.bazel_config }}
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
PLATFORM: ${{ matrix.platform }}
|
||||
SANDBOX: ${{ matrix.sandbox }}
|
||||
TARGET: ${{ matrix.target }}
|
||||
|
||||
@@ -79,8 +79,6 @@ jobs:
|
||||
|
||||
- name: Build codex and the code-mode host with Bazel
|
||||
id: build_bazel
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
@@ -181,7 +181,6 @@ jobs:
|
||||
|
||||
- name: Build Bazel V8 release pair
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
PLATFORM: ${{ matrix.platform }}
|
||||
SANDBOX: ${{ matrix.sandbox }}
|
||||
TARGET: ${{ matrix.target }}
|
||||
@@ -211,7 +210,6 @@ jobs:
|
||||
- name: Stage release pair
|
||||
env:
|
||||
BAZEL_CONFIG: ${{ matrix.bazel_config }}
|
||||
BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
PLATFORM: ${{ matrix.platform }}
|
||||
SANDBOX: ${{ matrix.sandbox }}
|
||||
TARGET: ${{ matrix.target }}
|
||||
|
||||
@@ -118,6 +118,7 @@ async fn selected_runtime_transport_stays_revoked(mode: RuntimeAuthMode) {
|
||||
RequestRouteTelemetry::for_endpoint("/responses"),
|
||||
&http::HeaderMap::new(),
|
||||
/*parent_routing_affinity*/ None,
|
||||
/*reauth*/ false,
|
||||
)
|
||||
.await;
|
||||
assert!(matches!(
|
||||
|
||||
+1
-50
@@ -76,20 +76,7 @@ configurations.
|
||||
|
||||
### All remote configurations
|
||||
|
||||
GitHub Actions routes Bazel build and output-resolution commands through
|
||||
`.github/scripts/run_bazel_with_buildbuddy.py`. Higher-level helpers such as
|
||||
`.github/scripts/run-bazel-ci.sh` and `.github/scripts/rusty_v8_bazel.py`
|
||||
delegate remote configuration selection to that wrapper. The wrapper reads the
|
||||
GitHub Actions repository and event payload rather than relying on workflow
|
||||
files to duplicate tenant-selection logic. It also normalizes GitHub Actions
|
||||
startup options so all Bazel launches in a job reuse the same server and
|
||||
in-memory analysis cache. Target-discovery and lockfile helpers delegate to the
|
||||
same wrapper so their callers do not need to select CI-specific startup options.
|
||||
|
||||
Loading-phase target-discovery `bazel query` commands run locally because they
|
||||
only enumerate labels and do not need remote caches or execution.
|
||||
|
||||
The `Cache/BES` host is also used for remote downloads.
|
||||
CI executes Bazel actions on its runners. The following configurations are available for explicit local use.
|
||||
|
||||
| Invocation/config | Key Required | Cache/BES | Build exec | Test exec |
|
||||
| ------------------------------------------- | ------------ | ---------------------- | ---------- | --------- |
|
||||
@@ -99,42 +86,6 @@ The `Cache/BES` host is also used for remote downloads.
|
||||
| `bazel ... --config=buildbuddy-openai` | Yes | `openai.buildbuddy.io` | Local | Local |
|
||||
| `bazel ... --config=buildbuddy-openai-rbe` | Yes | `openai.buildbuddy.io` | Remote | Remote |
|
||||
|
||||
Without an API key, the wrapper removes remote CI configurations and runs
|
||||
locally. With a key, workflows choose the host as follows:
|
||||
|
||||
| Run | Key | Uses OpenAI BuildBuddy Host |
|
||||
| ------------------------------------------------ | --- | --------------------------- |
|
||||
| Push to `main` in `openai/codex` | Yes | Yes |
|
||||
| `workflow_dispatch` in `openai/codex` | Yes | Yes |
|
||||
| Same-repository pull request in `openai/codex` | Yes | Yes |
|
||||
| Fork pull request into `openai/codex` | No | No; local |
|
||||
| Push or `workflow_dispatch` in a fork with a key | Yes | No; generic host |
|
||||
| Pull request run in a fork repository with a key | Yes | No; generic host |
|
||||
|
||||
CI configurations determine whether builds and tests execute remotely:
|
||||
|
||||
| CI config | Remote config | Build exec | Test exec |
|
||||
| ------------------- | ------------- | ----------- | ----------- |
|
||||
| `ci-linux` | `*-rbe` | Remote host | Remote host |
|
||||
| `ci-v8` | `*-rbe` | Remote host | Remote host |
|
||||
| `ci-macos` | `*-rbe` | Remote host | Local |
|
||||
| `ci-windows-cross` | `*-rbe` | Remote host | Local |
|
||||
| `ci-windows` | non-RBE | Local | Local |
|
||||
| Keyless CI fallback | none | Local | Local |
|
||||
|
||||
To exercise the generic remote configuration with your key:
|
||||
|
||||
```bash
|
||||
BUILDBUDDY_API_KEY=... GITHUB_REPOSITORY=my-fork/codex \
|
||||
./.github/scripts/run_bazel_with_buildbuddy.py \
|
||||
build --config=ci-linux //codex-rs/cli:codex
|
||||
```
|
||||
|
||||
The wrapper selects the OpenAI host only inside GitHub Actions for a trusted
|
||||
run in `openai/codex`. A missing or malformed pull request event
|
||||
payload fails closed to the generic host. For local OpenAI host access, use
|
||||
the `user.bazelrc` configuration above.
|
||||
|
||||
## Evolving the setup
|
||||
|
||||
When you add or change Rust dependencies, update the Cargo.toml/Cargo.lock as normal.
|
||||
|
||||
@@ -23,15 +23,16 @@ use codex_protocol::error::CodexErr;
|
||||
use codex_protocol::error::Result;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::Weak;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::sync::OnceCell;
|
||||
|
||||
/// Shared launchers opened by the existing board factory when the MCP flag is enabled.
|
||||
#[derive(Default)]
|
||||
pub struct McpBoards {
|
||||
servers: Mutex<HashMap<SessionId, Weak<LocalServer>>>,
|
||||
servers: Mutex<HashMap<SessionId, Weak<OnceCell<LocalServer>>>>,
|
||||
}
|
||||
struct Binding(Arc<LocalServer>);
|
||||
struct Binding(Arc<OnceCell<LocalServer>>);
|
||||
struct PendingMcpRefresh;
|
||||
|
||||
impl McpBoards {
|
||||
@@ -42,25 +43,28 @@ impl McpBoards {
|
||||
caller: ThreadId,
|
||||
host: Arc<dyn MessageBoardHost>,
|
||||
) -> Result<()> {
|
||||
let mut servers = self.servers.lock().await;
|
||||
servers.retain(|_, server| server.strong_count() > 0);
|
||||
let server = match servers.get(&tree).and_then(Weak::upgrade) {
|
||||
Some(server) => server,
|
||||
None => {
|
||||
let server = Arc::new(
|
||||
launch_in_memory()
|
||||
.await
|
||||
.map_err(|error| CodexErr::Io(std::io::Error::other(error)))?,
|
||||
);
|
||||
servers.insert(tree, Arc::downgrade(&server));
|
||||
server
|
||||
}
|
||||
let slot = {
|
||||
let mut servers = self
|
||||
.servers
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
servers.retain(|_, server| server.strong_count() > 0);
|
||||
let entry = servers.entry(tree).or_default();
|
||||
entry.upgrade().unwrap_or_else(|| {
|
||||
let slot = Arc::new(OnceCell::new());
|
||||
*entry = Arc::downgrade(&slot);
|
||||
slot
|
||||
})
|
||||
};
|
||||
let server = slot
|
||||
.get_or_try_init(launch_in_memory)
|
||||
.await
|
||||
.map_err(|error| CodexErr::Io(std::io::Error::other(error)))?;
|
||||
server
|
||||
.bind_agent(tree, caller, host)
|
||||
.await
|
||||
.map_err(|error| CodexErr::Io(std::io::Error::other(error)))?;
|
||||
store.insert(Binding(server));
|
||||
store.insert(Binding(slot));
|
||||
store.insert(PendingMcpRefresh);
|
||||
Ok(())
|
||||
}
|
||||
@@ -96,18 +100,21 @@ impl<C: Sync> McpServerContributor<C> for McpBoards {
|
||||
Box::pin(async move {
|
||||
let Some(binding) = context
|
||||
.thread_store()
|
||||
.and_then(|store| store.get::<Binding>())
|
||||
.and_then(ExtensionData::get::<Binding>)
|
||||
else {
|
||||
return Vec::new();
|
||||
};
|
||||
let Ok(authorization) = binding.0.authorization().to_str() else {
|
||||
let Some(server) = binding.0.get() else {
|
||||
return Vec::new();
|
||||
};
|
||||
let Ok(authorization) = server.authorization().to_str() else {
|
||||
return Vec::new();
|
||||
};
|
||||
vec![McpServerContribution::Set {
|
||||
name: "codex_message_board".into(),
|
||||
config: Box::new(McpServerConfig {
|
||||
transport: McpServerTransportConfig::StreamableHttp {
|
||||
url: binding.0.url().into(),
|
||||
url: server.url().into(),
|
||||
bearer_token_env_var: None,
|
||||
http_headers: Some([("Authorization".into(), authorization.into())].into()),
|
||||
env_http_headers: None,
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
load("//:defs.bzl", "codex_rust_crate")
|
||||
|
||||
exports_files(
|
||||
["tests/common/mod.rs"],
|
||||
visibility = ["//codex-rs/core:__pkg__"],
|
||||
)
|
||||
|
||||
codex_rust_crate(
|
||||
name = "message-board",
|
||||
crate_name = "codex_message_board",
|
||||
|
||||
@@ -78,7 +78,7 @@ async fn empty_thread_backend_chord_preserves_draft_until_first_submission() ->
|
||||
.apply_external_edit("first draft".to_string());
|
||||
app.chat_widget
|
||||
.set_new_backend_control(Some("Cloud".to_string()));
|
||||
let screen = render_bottom_popup(&app.chat_widget, 80);
|
||||
let screen = render_bottom_popup(&app.chat_widget, /*width*/ 80);
|
||||
insta::assert_snapshot!(screen.lines().find(|line| line.trim_start().starts_with("Cloud")).unwrap().trim(), @"Cloud ⌃x b to cycle");
|
||||
|
||||
// Cursor movement remains available while the backend selector is visible.
|
||||
@@ -110,7 +110,7 @@ async fn empty_thread_backend_chord_preserves_draft_until_first_submission() ->
|
||||
|
||||
app.chat_widget.handle_key_event(KeyCode::Enter.into());
|
||||
assert!(
|
||||
!render_bottom_popup(&app.chat_widget, 80)
|
||||
!render_bottom_popup(&app.chat_widget, /*width*/ 80)
|
||||
.lines()
|
||||
.any(|line| line.trim_start().starts_with("Cloud"))
|
||||
);
|
||||
|
||||
@@ -4789,7 +4789,7 @@ fn fresh_session_keeps_its_name_and_draft_when_cycling_backends() -> Result<()>
|
||||
backends.session_at_mut(backends.displayed),
|
||||
AppEvent::ChooseNewSessionCheckout { name: None },
|
||||
).await?;
|
||||
assert!(render_bottom_popup(&app.chat_widget, 80).contains("Use current Git worktree"));
|
||||
assert!(render_bottom_popup(&app.chat_widget, /*width*/ 80).contains("Use current Git worktree"));
|
||||
app.chat_widget.handle_key_event(KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE));
|
||||
assert_eq!(app.current_displayed_thread_id(), Some(thread_id));
|
||||
assert_eq!(recorded_params(&requests, "thread/start").len(), 1);
|
||||
|
||||
@@ -577,7 +577,7 @@ impl ChatWidget {
|
||||
}
|
||||
|
||||
pub(super) fn restore_composer_state(&mut self, composer: ThreadComposerState) {
|
||||
self.restore_composer_state_with_shell_mode(composer, None);
|
||||
self.restore_composer_state_with_shell_mode(composer, /*shell_mode*/ None);
|
||||
}
|
||||
|
||||
fn restore_composer_state_with_shell_mode(
|
||||
|
||||
@@ -1184,7 +1184,7 @@ async fn startup_draft_handoff_preserves_literal_and_shell_bang() {
|
||||
] {
|
||||
let (mut source, _rx, _ops) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||
source.bottom_pane.insert_str(&format!("x{text}"));
|
||||
source.bottom_pane.set_composer_cursor(0);
|
||||
source.bottom_pane.set_composer_cursor(/*cursor*/ 0);
|
||||
source.handle_key_event(KeyEvent::from(KeyCode::Delete));
|
||||
let draft = source.composer_draft_snapshot();
|
||||
assert_eq!(draft.text, text);
|
||||
|
||||
@@ -183,8 +183,10 @@ pub(crate) fn quiet_workspace_style() -> Style {
|
||||
let Some(bg) = default_bg() else {
|
||||
return base.fg(Color::Reset).bg(Color::Reset).dim();
|
||||
};
|
||||
let fill = best_color(blend(user_message_bg_rgb(bg), bg, 0.40));
|
||||
let foreground = default_fg().map_or(Color::Reset, |fg| best_color(blend(fg, bg, 0.66)));
|
||||
let fill = best_color(blend(user_message_bg_rgb(bg), bg, /*alpha*/ 0.40));
|
||||
let foreground = default_fg().map_or(Color::Reset, |fg| {
|
||||
best_color(blend(fg, bg, /*alpha*/ 0.66))
|
||||
});
|
||||
base.bg(fill).fg(readable_color_on(foreground, Some(fill)))
|
||||
}
|
||||
|
||||
|
||||
@@ -365,11 +365,11 @@ impl TranscriptView {
|
||||
lines.extend_from_slice(auxiliary);
|
||||
(!lines.is_empty()).then_some(lines)
|
||||
};
|
||||
self.sync_search_live_tail(width, None, lines);
|
||||
self.sync_search_live_tail(width, /*key*/ None, lines);
|
||||
if self.detailed {
|
||||
self.sync_live_tail(width, None, lines);
|
||||
self.sync_live_tail(width, /*key*/ None, lines);
|
||||
} else {
|
||||
self.sync_live_activity_tail(width, None, expanded && disclose, |width| {
|
||||
self.sync_live_activity_tail(width, /*key*/ None, expanded && disclose, |width| {
|
||||
let activity = active.map_or_else(Vec::new, |cell| {
|
||||
if disclose && expanded {
|
||||
cell.expanded_hyperlink_lines(width)
|
||||
|
||||
+1
-5
@@ -7,9 +7,6 @@ inputs:
|
||||
windows-tools:
|
||||
description: Directory containing the public Windows voice bootstrap
|
||||
default: .github/scripts
|
||||
buildbuddy-api-key:
|
||||
description: Optional BuildBuddy credential for trusted CI builds
|
||||
default: ""
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
@@ -23,14 +20,13 @@ runs:
|
||||
cache-scope: cargo-voice-native
|
||||
- name: Set up Windows voice build tools
|
||||
if: runner.os == 'Windows'
|
||||
uses: ./third_party/voice/cargo-ci/windows-setup
|
||||
uses: ./.github/actions/setup-bazel-windows
|
||||
with:
|
||||
target: ${{ inputs.target }}
|
||||
windows-tools: ${{ inputs.windows-tools }}
|
||||
- name: Build and stage native dependencies
|
||||
shell: bash
|
||||
env:
|
||||
BUILDBUDDY_API_KEY: ${{ inputs.buildbuddy-api-key }}
|
||||
TARGET: ${{ inputs.target }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
name: Set up Windows voice build tools
|
||||
description: Prepare verified native Windows voice tools for Bazel.
|
||||
inputs:
|
||||
target:
|
||||
description: Native Windows target triple
|
||||
required: true
|
||||
windows-tools:
|
||||
description: Directory containing the public Windows voice bootstrap
|
||||
default: .github/scripts
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: ./.github/actions/setup-msvc-env
|
||||
with:
|
||||
target: ${{ inputs.target }}
|
||||
- name: Install verified public Windows tools
|
||||
shell: pwsh
|
||||
env:
|
||||
WINDOWS_TOOLS: ${{ inputs.windows-tools }}
|
||||
TARGET: ${{ inputs.target }}
|
||||
run: |
|
||||
./.github/scripts/compute-bazel-windows-path.ps1
|
||||
$manifest = Get-Content -Raw "$env:WINDOWS_TOOLS/voice-cygwin-snapshot.json" | ConvertFrom-Json
|
||||
$pin = $manifest.archive
|
||||
$archive = Join-Path $env:RUNNER_TEMP $pin.name
|
||||
Invoke-WebRequest "https://github.com/openai/codex/releases/download/$($pin.tag)/$($pin.name)" -OutFile $archive
|
||||
& "$env:WINDOWS_TOOLS/setup-voice-windows.ps1" -Target $env:TARGET -SnapshotArchive $archive
|
||||
if (-not $env:SystemRoot) { throw "Windows SystemRoot is required" }
|
||||
"VOICE_WINDOWS_SYSTEM_ROOT=$env:SystemRoot" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
$hostArch = $env:PROCESSOR_ARCHITEW6432
|
||||
if (-not $hostArch) { $hostArch = $env:PROCESSOR_ARCHITECTURE }
|
||||
if (-not $hostArch) { throw "Windows host architecture is required" }
|
||||
"VOICE_WINDOWS_HOST_ARCH=$hostArch" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
Reference in New Issue
Block a user