mirror of
https://github.com/openai/codex.git
synced 2026-02-01 22:47:52 +00:00
feat: introduce find_resource! macro that works with Cargo or Bazel (#8879)
To support Bazelification in https://github.com/openai/codex/pull/8875, this PR introduces a new `find_resource!` macro that we use in place of our existing logic in tests that looks for resources relative to the compile-time `CARGO_MANIFEST_DIR` env var. To make this work, we plan to add the following to all `rust_library()` and `rust_test()` Bazel rules in the project: ``` rustc_env = { "BAZEL_PACKAGE": native.package_name(), }, ``` Our new `find_resource!` macro reads this value via `option_env!("BAZEL_PACKAGE")` so that the Bazel package _of the code using `find_resource!`_ is injected into the code expanded from the macro. (If `find_resource()` were a function, then `option_env!("BAZEL_PACKAGE")` would always be `codex-rs/utils/cargo-bin`, which is not what we want.) Note we only consider the `BAZEL_PACKAGE` value when the `RUNFILES_DIR` environment variable is set at runtime, indicating that the test is being run by Bazel. In this case, we have to concatenate the runtime `RUNFILES_DIR` with the compile-time `BAZEL_PACKAGE` value to build the path to the resource. In testing this change, I discovered one funky edge case in `codex-rs/exec-server/tests/common/lib.rs` where we have to _normalize_ (but not canonicalize!) the result from `find_resource!` because the path contains a `common/..` component that does not exist on disk when the test is run under Bazel, so it must be semantically normalized using the [`path-absolutize`](https://crates.io/crates/path-absolutize) crate before it is passed to `dotslash fetch`. Because this new behavior may be non-obvious, this PR also updates `AGENTS.md` to make humans/Codex aware that this API is preferred.
This commit is contained in:
@@ -77,11 +77,11 @@ If you don’t have the tool:
|
||||
- Prefer deep equals comparisons whenever possible. Perform `assert_eq!()` on entire objects, rather than individual fields.
|
||||
- Avoid mutating process environment in tests; prefer passing environment-derived flags or dependencies from above.
|
||||
|
||||
### Spawning workspace binaries in tests (Cargo vs Buck2)
|
||||
### Spawning workspace binaries in tests (Cargo vs Bazel)
|
||||
|
||||
- Prefer `codex_utils_cargo_bin::cargo_bin("...")` over `assert_cmd::Command::cargo_bin(...)` or `escargot` when tests need to spawn first-party binaries.
|
||||
- Under Buck2, `CARGO_BIN_EXE_*` may be project-relative (e.g. `buck-out/...`), which breaks if a test changes its working directory. `codex_utils_cargo_bin::cargo_bin` resolves to an absolute path first.
|
||||
- When locating fixture files under Buck2, avoid `env!("CARGO_MANIFEST_DIR")` (Buck codegen sets it to `"."`). Prefer deriving paths from `codex_utils_cargo_bin::buck_project_root()` when needed.
|
||||
- Under Bazel, binaries and resources may live under runfiles; use `codex_utils_cargo_bin::cargo_bin` to resolve absolute paths that remain stable after `chdir`.
|
||||
- When locating fixture files or test resources under Bazel, avoid `env!("CARGO_MANIFEST_DIR")`. Prefer `codex_utils_cargo_bin::find_resource!` so paths resolve correctly under both Cargo and Bazel runfiles.
|
||||
|
||||
### Integration tests (core)
|
||||
|
||||
|
||||
2
codex-rs/Cargo.lock
generated
2
codex-rs/Cargo.lock
generated
@@ -1129,6 +1129,7 @@ dependencies = [
|
||||
"codex-common",
|
||||
"codex-core",
|
||||
"codex-git",
|
||||
"codex-utils-cargo-bin",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
@@ -2844,6 +2845,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"codex-core",
|
||||
"codex-utils-cargo-bin",
|
||||
"path-absolutize",
|
||||
"rmcp",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use codex_utils_cargo_bin::find_resource;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs;
|
||||
@@ -8,7 +9,7 @@ use tempfile::tempdir;
|
||||
|
||||
#[test]
|
||||
fn test_apply_patch_scenarios() -> anyhow::Result<()> {
|
||||
let scenarios_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/scenarios");
|
||||
let scenarios_dir = find_resource!("tests/fixtures/scenarios")?;
|
||||
for scenario in fs::read_dir(scenarios_dir)? {
|
||||
let scenario = scenario?;
|
||||
let path = scenario.path();
|
||||
|
||||
@@ -12,6 +12,7 @@ anyhow = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive"] }
|
||||
codex-common = { workspace = true, features = ["cli"] }
|
||||
codex-core = { workspace = true }
|
||||
codex-utils-cargo-bin = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use codex_chatgpt::apply_command::apply_diff_from_task;
|
||||
use codex_chatgpt::get_task::GetTaskResponse;
|
||||
use std::path::Path;
|
||||
use codex_utils_cargo_bin::find_resource;
|
||||
use tempfile::TempDir;
|
||||
use tokio::process::Command;
|
||||
|
||||
@@ -68,7 +68,7 @@ async fn create_temp_git_repo() -> anyhow::Result<TempDir> {
|
||||
}
|
||||
|
||||
async fn mock_get_task_with_fixture() -> anyhow::Result<GetTaskResponse> {
|
||||
let fixture_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/task_turn_fixture.json");
|
||||
let fixture_path = find_resource!("tests/task_turn_fixture.json")?;
|
||||
let fixture_content = tokio::fs::read_to_string(fixture_path).await?;
|
||||
let response: GetTaskResponse = serde_json::from_str(&fixture_content)?;
|
||||
Ok(response)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use assert_cmd::Command as AssertCommand;
|
||||
use codex_core::RolloutRecorder;
|
||||
use codex_core::protocol::GitInfo;
|
||||
use codex_utils_cargo_bin::find_resource;
|
||||
use core_test_support::fs_wait;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use std::time::Duration;
|
||||
@@ -12,6 +13,16 @@ use wiremock::ResponseTemplate;
|
||||
use wiremock::matchers::method;
|
||||
use wiremock::matchers::path;
|
||||
|
||||
fn repo_root() -> std::path::PathBuf {
|
||||
#[expect(clippy::expect_used)]
|
||||
find_resource!(".").expect("failed to resolve repo root")
|
||||
}
|
||||
|
||||
fn cli_responses_fixture() -> std::path::PathBuf {
|
||||
#[expect(clippy::expect_used)]
|
||||
find_resource!("tests/cli_responses_fixture.sse").expect("failed to resolve fixture path")
|
||||
}
|
||||
|
||||
/// Tests streaming chat completions through the CLI using a mock server.
|
||||
/// This test:
|
||||
/// 1. Sets up a mock server that simulates OpenAI's chat completions API
|
||||
@@ -23,6 +34,7 @@ async fn chat_mode_stream_cli() {
|
||||
skip_if_no_network!();
|
||||
|
||||
let server = MockServer::start().await;
|
||||
let repo_root = repo_root();
|
||||
let sse = concat!(
|
||||
"data: {\"choices\":[{\"delta\":{\"content\":\"hi\"}}]}\n\n",
|
||||
"data: {\"choices\":[{\"delta\":{}}]}\n\n",
|
||||
@@ -53,7 +65,7 @@ async fn chat_mode_stream_cli() {
|
||||
.arg("-c")
|
||||
.arg("model_provider=\"mock\"")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg("hello?");
|
||||
cmd.env("CODEX_HOME", home.path())
|
||||
.env("OPENAI_API_KEY", "dummy")
|
||||
@@ -127,6 +139,7 @@ async fn exec_cli_applies_experimental_instructions_file() {
|
||||
);
|
||||
|
||||
let home = TempDir::new().unwrap();
|
||||
let repo_root = repo_root();
|
||||
let bin = codex_utils_cargo_bin::cargo_bin("codex").unwrap();
|
||||
let mut cmd = AssertCommand::new(bin);
|
||||
cmd.arg("exec")
|
||||
@@ -140,7 +153,7 @@ async fn exec_cli_applies_experimental_instructions_file() {
|
||||
"experimental_instructions_file=\"{custom_path_str}\""
|
||||
))
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg("hello?\n");
|
||||
cmd.env("CODEX_HOME", home.path())
|
||||
.env("OPENAI_API_KEY", "dummy")
|
||||
@@ -177,8 +190,8 @@ async fn exec_cli_applies_experimental_instructions_file() {
|
||||
async fn responses_api_stream_cli() {
|
||||
skip_if_no_network!();
|
||||
|
||||
let fixture =
|
||||
std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/cli_responses_fixture.sse");
|
||||
let fixture = cli_responses_fixture();
|
||||
let repo_root = repo_root();
|
||||
|
||||
let home = TempDir::new().unwrap();
|
||||
let bin = codex_utils_cargo_bin::cargo_bin("codex").unwrap();
|
||||
@@ -186,7 +199,7 @@ async fn responses_api_stream_cli() {
|
||||
cmd.arg("exec")
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg("hello?");
|
||||
cmd.env("CODEX_HOME", home.path())
|
||||
.env("OPENAI_API_KEY", "dummy")
|
||||
@@ -213,8 +226,8 @@ async fn integration_creates_and_checks_session_file() -> anyhow::Result<()> {
|
||||
let prompt = format!("echo {marker}");
|
||||
|
||||
// 3. Use the same offline SSE fixture as responses_api_stream_cli so the test is hermetic.
|
||||
let fixture =
|
||||
std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/cli_responses_fixture.sse");
|
||||
let fixture = cli_responses_fixture();
|
||||
let repo_root = repo_root();
|
||||
|
||||
// 4. Run the codex CLI and invoke `exec`, which is what records a session.
|
||||
let bin = codex_utils_cargo_bin::cargo_bin("codex").unwrap();
|
||||
@@ -222,7 +235,7 @@ async fn integration_creates_and_checks_session_file() -> anyhow::Result<()> {
|
||||
cmd.arg("exec")
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg(&prompt);
|
||||
cmd.env("CODEX_HOME", home.path())
|
||||
.env("OPENAI_API_KEY", "dummy")
|
||||
@@ -343,7 +356,7 @@ async fn integration_creates_and_checks_session_file() -> anyhow::Result<()> {
|
||||
cmd2.arg("exec")
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg(&prompt2)
|
||||
.arg("resume")
|
||||
.arg("--last");
|
||||
|
||||
@@ -11,6 +11,7 @@ path = "lib.rs"
|
||||
anyhow = { workspace = true }
|
||||
codex-core = { workspace = true }
|
||||
codex-utils-cargo-bin = { workspace = true }
|
||||
path-absolutize = { workspace = true }
|
||||
rmcp = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use codex_core::MCP_SANDBOX_STATE_METHOD;
|
||||
use codex_core::SandboxState;
|
||||
use codex_core::protocol::SandboxPolicy;
|
||||
use codex_utils_cargo_bin::find_resource;
|
||||
use path_absolutize::Absolutize;
|
||||
use rmcp::ClientHandler;
|
||||
use rmcp::ErrorData as McpError;
|
||||
use rmcp::RoleClient;
|
||||
@@ -35,16 +37,15 @@ where
|
||||
let mcp_executable = codex_utils_cargo_bin::cargo_bin("codex-exec-mcp-server")?;
|
||||
let execve_wrapper = codex_utils_cargo_bin::cargo_bin("codex-execve-wrapper")?;
|
||||
|
||||
// `bash` requires a special lookup when running under Bazel because it is a
|
||||
// _resource_ rather than a binary target.
|
||||
let bash = if let Some(bazel_runfiles_dir) = std::env::var_os("RUNFILES_DIR") {
|
||||
PathBuf::from(bazel_runfiles_dir).join("_main/codex-rs/exec-server/tests/suite/bash")
|
||||
} else {
|
||||
Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("..")
|
||||
.join("suite")
|
||||
.join("bash")
|
||||
};
|
||||
// `bash` is a test resource rather than a binary target, so we must use
|
||||
// `find_resource!` to locate it instead of `cargo_bin`.
|
||||
//
|
||||
// Note we also have to normalize (but not canonicalize!) the path for
|
||||
// _Bazel_ because the original value ends with
|
||||
// `codex-rs/exec-server/tests/common/../suite/bash`, but the `tests/common`
|
||||
// folder will not exist at runtime under Bazel. As such, we have to
|
||||
// normalize it before passing it to `dotslash fetch`.
|
||||
let bash = find_resource!("../suite/bash")?.absolutize()?.to_path_buf();
|
||||
|
||||
// Need to ensure the artifact associated with the bash DotSlash file is
|
||||
// available before it is run in a read-only sandbox.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#![allow(clippy::unwrap_used, clippy::expect_used)]
|
||||
use codex_utils_cargo_bin::find_resource;
|
||||
use core_test_support::responses::ev_completed;
|
||||
use core_test_support::responses::mount_sse_once_match;
|
||||
use core_test_support::responses::sse;
|
||||
@@ -10,6 +11,7 @@ use wiremock::matchers::header;
|
||||
async fn exec_uses_codex_api_key_env_var() -> anyhow::Result<()> {
|
||||
let test = test_codex_exec();
|
||||
let server = start_mock_server().await;
|
||||
let repo_root = find_resource!(".")?;
|
||||
|
||||
mount_sse_once_match(
|
||||
&server,
|
||||
@@ -21,7 +23,7 @@ async fn exec_uses_codex_api_key_env_var() -> anyhow::Result<()> {
|
||||
test.cmd_with_server(&server)
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg("echo testing codex api key")
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#![allow(clippy::unwrap_used, clippy::expect_used)]
|
||||
use anyhow::Context;
|
||||
use codex_utils_cargo_bin::find_resource;
|
||||
use core_test_support::test_codex_exec::test_codex_exec;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::Value;
|
||||
use std::path::Path;
|
||||
use std::string::ToString;
|
||||
use uuid::Uuid;
|
||||
use walkdir::WalkDir;
|
||||
@@ -103,11 +103,19 @@ fn last_user_image_count(path: &std::path::Path) -> usize {
|
||||
last_count
|
||||
}
|
||||
|
||||
fn exec_fixture() -> anyhow::Result<std::path::PathBuf> {
|
||||
Ok(find_resource!("tests/fixtures/cli_responses_fixture.sse")?)
|
||||
}
|
||||
|
||||
fn exec_repo_root() -> anyhow::Result<std::path::PathBuf> {
|
||||
Ok(find_resource!(".")?)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_resume_last_appends_to_existing_file() -> anyhow::Result<()> {
|
||||
let test = test_codex_exec();
|
||||
let fixture =
|
||||
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/cli_responses_fixture.sse");
|
||||
let fixture = exec_fixture()?;
|
||||
let repo_root = exec_repo_root()?;
|
||||
|
||||
// 1) First run: create a session with a unique marker in the content.
|
||||
let marker = format!("resume-last-{}", Uuid::new_v4());
|
||||
@@ -118,7 +126,7 @@ fn exec_resume_last_appends_to_existing_file() -> anyhow::Result<()> {
|
||||
.env("OPENAI_BASE_URL", "http://unused.local")
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg(&prompt)
|
||||
.assert()
|
||||
.success();
|
||||
@@ -137,7 +145,7 @@ fn exec_resume_last_appends_to_existing_file() -> anyhow::Result<()> {
|
||||
.env("OPENAI_BASE_URL", "http://unused.local")
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg(&prompt2)
|
||||
.arg("resume")
|
||||
.arg("--last")
|
||||
@@ -160,8 +168,8 @@ fn exec_resume_last_appends_to_existing_file() -> anyhow::Result<()> {
|
||||
#[test]
|
||||
fn exec_resume_last_accepts_prompt_after_flag_in_json_mode() -> anyhow::Result<()> {
|
||||
let test = test_codex_exec();
|
||||
let fixture =
|
||||
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/cli_responses_fixture.sse");
|
||||
let fixture = exec_fixture()?;
|
||||
let repo_root = exec_repo_root()?;
|
||||
|
||||
// 1) First run: create a session with a unique marker in the content.
|
||||
let marker = format!("resume-last-json-{}", Uuid::new_v4());
|
||||
@@ -172,7 +180,7 @@ fn exec_resume_last_accepts_prompt_after_flag_in_json_mode() -> anyhow::Result<(
|
||||
.env("OPENAI_BASE_URL", "http://unused.local")
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg(&prompt)
|
||||
.assert()
|
||||
.success();
|
||||
@@ -191,7 +199,7 @@ fn exec_resume_last_accepts_prompt_after_flag_in_json_mode() -> anyhow::Result<(
|
||||
.env("OPENAI_BASE_URL", "http://unused.local")
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg("--json")
|
||||
.arg("resume")
|
||||
.arg("--last")
|
||||
@@ -214,8 +222,7 @@ fn exec_resume_last_accepts_prompt_after_flag_in_json_mode() -> anyhow::Result<(
|
||||
#[test]
|
||||
fn exec_resume_accepts_global_flags_after_subcommand() -> anyhow::Result<()> {
|
||||
let test = test_codex_exec();
|
||||
let fixture =
|
||||
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/cli_responses_fixture.sse");
|
||||
let fixture = exec_fixture()?;
|
||||
|
||||
// Seed a session.
|
||||
test.cmd()
|
||||
@@ -249,8 +256,8 @@ fn exec_resume_accepts_global_flags_after_subcommand() -> anyhow::Result<()> {
|
||||
#[test]
|
||||
fn exec_resume_by_id_appends_to_existing_file() -> anyhow::Result<()> {
|
||||
let test = test_codex_exec();
|
||||
let fixture =
|
||||
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/cli_responses_fixture.sse");
|
||||
let fixture = exec_fixture()?;
|
||||
let repo_root = exec_repo_root()?;
|
||||
|
||||
// 1) First run: create a session
|
||||
let marker = format!("resume-by-id-{}", Uuid::new_v4());
|
||||
@@ -261,7 +268,7 @@ fn exec_resume_by_id_appends_to_existing_file() -> anyhow::Result<()> {
|
||||
.env("OPENAI_BASE_URL", "http://unused.local")
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg(&prompt)
|
||||
.assert()
|
||||
.success();
|
||||
@@ -284,7 +291,7 @@ fn exec_resume_by_id_appends_to_existing_file() -> anyhow::Result<()> {
|
||||
.env("OPENAI_BASE_URL", "http://unused.local")
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg(&prompt2)
|
||||
.arg("resume")
|
||||
.arg(&session_id)
|
||||
@@ -306,8 +313,8 @@ fn exec_resume_by_id_appends_to_existing_file() -> anyhow::Result<()> {
|
||||
#[test]
|
||||
fn exec_resume_preserves_cli_configuration_overrides() -> anyhow::Result<()> {
|
||||
let test = test_codex_exec();
|
||||
let fixture =
|
||||
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/cli_responses_fixture.sse");
|
||||
let fixture = exec_fixture()?;
|
||||
let repo_root = exec_repo_root()?;
|
||||
|
||||
let marker = format!("resume-config-{}", Uuid::new_v4());
|
||||
let prompt = format!("echo {marker}");
|
||||
@@ -321,7 +328,7 @@ fn exec_resume_preserves_cli_configuration_overrides() -> anyhow::Result<()> {
|
||||
.arg("--model")
|
||||
.arg("gpt-5.1")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg(&prompt)
|
||||
.assert()
|
||||
.success();
|
||||
@@ -343,7 +350,7 @@ fn exec_resume_preserves_cli_configuration_overrides() -> anyhow::Result<()> {
|
||||
.arg("--model")
|
||||
.arg("gpt-5.1-high")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg(&prompt2)
|
||||
.arg("resume")
|
||||
.arg("--last")
|
||||
@@ -382,8 +389,8 @@ fn exec_resume_preserves_cli_configuration_overrides() -> anyhow::Result<()> {
|
||||
#[test]
|
||||
fn exec_resume_accepts_images_after_subcommand() -> anyhow::Result<()> {
|
||||
let test = test_codex_exec();
|
||||
let fixture =
|
||||
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/cli_responses_fixture.sse");
|
||||
let fixture = exec_fixture()?;
|
||||
let repo_root = exec_repo_root()?;
|
||||
|
||||
let marker = format!("resume-image-{}", Uuid::new_v4());
|
||||
let prompt = format!("echo {marker}");
|
||||
@@ -393,7 +400,7 @@ fn exec_resume_accepts_images_after_subcommand() -> anyhow::Result<()> {
|
||||
.env("OPENAI_BASE_URL", "http://unused.local")
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg(&prompt)
|
||||
.assert()
|
||||
.success();
|
||||
@@ -417,7 +424,7 @@ fn exec_resume_accepts_images_after_subcommand() -> anyhow::Result<()> {
|
||||
.env("OPENAI_BASE_URL", "http://unused.local")
|
||||
.arg("--skip-git-repo-check")
|
||||
.arg("-C")
|
||||
.arg(env!("CARGO_MANIFEST_DIR"))
|
||||
.arg(&repo_root)
|
||||
.arg("resume")
|
||||
.arg("--last")
|
||||
.arg("--image")
|
||||
|
||||
@@ -70,6 +70,43 @@ fn cargo_bin_env_keys(name: &str) -> Vec<String> {
|
||||
keys
|
||||
}
|
||||
|
||||
/// Macro that derives the path to a test resource at runtime, the value of
|
||||
/// which depends on whether Cargo or Bazel is being used to build and run a
|
||||
/// test. Note the return value may be a relative or absolute path.
|
||||
/// (Incidentally, this is a macro rather than a function because it reads
|
||||
/// compile-time environment variables that need to be captured at the call
|
||||
/// site.)
|
||||
///
|
||||
/// This is expected to be used exclusively in test code because Codex CLI is a
|
||||
/// standalone binary with no packaged resources.
|
||||
#[macro_export]
|
||||
macro_rules! find_resource {
|
||||
($resource:expr) => {{
|
||||
// When this code is built and run with Bazel:
|
||||
// - we inject `BAZEL_PACKAGE` as a compile-time environment variable
|
||||
// that points to native.package_name()
|
||||
// - at runtime, Bazel will set `RUNFILES_DIR` to the runfiles directory
|
||||
//
|
||||
// Therefore, the compile-time value of `BAZEL_PACKAGE` will always be
|
||||
// included in the compiled binary (even if it is built with Cargo), but
|
||||
// we only check it at runtime if `RUNFILES_DIR` is set.
|
||||
let resource = std::path::Path::new(&$resource);
|
||||
let manifest_dir = match std::env::var("RUNFILES_DIR") {
|
||||
Ok(bazel_runtime_files) => match option_env!("BAZEL_PACKAGE") {
|
||||
Some(bazel_package) => Ok(std::path::PathBuf::from(bazel_runtime_files)
|
||||
.join("_main")
|
||||
.join(bazel_package)),
|
||||
None => Err(std::io::Error::new(
|
||||
std::io::ErrorKind::NotFound,
|
||||
"BAZEL_PACKAGE not set in Bazel build",
|
||||
)),
|
||||
},
|
||||
Err(_) => Ok(std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))),
|
||||
};
|
||||
manifest_dir.map(|dir| dir.join(resource))
|
||||
}};
|
||||
}
|
||||
|
||||
fn resolve_bin_from_env(key: &str, value: OsString) -> Result<PathBuf, CargoBinError> {
|
||||
let abs = absolutize_from_buck_or_cwd(PathBuf::from(value))?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user