mirror of
https://github.com/openai/codex.git
synced 2026-11-03 19:53:25 +00:00
# Summary The standalone update action currently downloads and runs the Codex installer as an interactive command. When an existing managed Codex install is present, accepting an update can therefore enter an installer prompt instead of completing the update. This change runs the standalone installer with `CODEX_NON_INTERACTIVE=1` on macOS/Linux and Windows. The installer environment-variable support is introduced by the parent PR; this PR wires that behavior into the Codex CLI update action. The rendered Windows command remains shell-safe, and long update commands wrap within the update-notice card. The standard test target snapshots the standalone notice for both platforms. # Stack 1. [#21567](https://github.com/openai/codex/pull/21567) - Adds environment-controlled release selection and noninteractive installer behavior. 2. [#24637](https://github.com/openai/codex/pull/24637) - Runs standalone updates with `CODEX_NON_INTERACTIVE=1`. (current) 3. [#24639](https://github.com/openai/codex/pull/24639) - Removes explicit release argument inputs in favor of `CODEX_RELEASE`. # Evidence Standalone updater-shaped macOS install with an existing npm-managed Codex on `PATH`: https://github.com/user-attachments/assets/a27fe9e9-db3a-4c39-a514-24bd3d1f01e8 # Testing Tests: targeted `codex-tui` update-action and update-notice snapshot tests, Rust formatting, benchmark smoke validation, macOS live-terminal standalone-update smoke testing, Windows ARM64 PowerShell standalone-update smoke testing through Parallels, and CI.
166 lines
6.0 KiB
Rust
166 lines
6.0 KiB
Rust
#[cfg(any(not(debug_assertions), test))]
|
|
use codex_install_context::InstallContext;
|
|
#[cfg(any(not(debug_assertions), test))]
|
|
use codex_install_context::InstallMethod;
|
|
#[cfg(any(not(debug_assertions), test))]
|
|
use codex_install_context::StandalonePlatform;
|
|
|
|
/// Update action the CLI should perform after the TUI exits.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum UpdateAction {
|
|
/// Update via `npm install -g @openai/codex@latest`.
|
|
NpmGlobalLatest,
|
|
/// Update via `bun install -g @openai/codex@latest`.
|
|
BunGlobalLatest,
|
|
/// Update via `brew upgrade codex`.
|
|
BrewUpgrade,
|
|
/// Update via `curl -fsSL https://chatgpt.com/codex/install.sh | CODEX_NON_INTERACTIVE=1 sh`.
|
|
StandaloneUnix,
|
|
/// Update via `$env:CODEX_NON_INTERACTIVE=1; irm https://chatgpt.com/codex/install.ps1 | iex`.
|
|
StandaloneWindows,
|
|
}
|
|
|
|
impl UpdateAction {
|
|
#[cfg(any(not(debug_assertions), test))]
|
|
pub(crate) fn from_install_context(context: &InstallContext) -> Option<Self> {
|
|
match &context.method {
|
|
InstallMethod::Npm => Some(UpdateAction::NpmGlobalLatest),
|
|
InstallMethod::Bun => Some(UpdateAction::BunGlobalLatest),
|
|
InstallMethod::Brew => Some(UpdateAction::BrewUpgrade),
|
|
InstallMethod::Standalone { platform, .. } => Some(match platform {
|
|
StandalonePlatform::Unix => UpdateAction::StandaloneUnix,
|
|
StandalonePlatform::Windows => UpdateAction::StandaloneWindows,
|
|
}),
|
|
InstallMethod::Other => None,
|
|
}
|
|
}
|
|
|
|
/// Returns the list of command-line arguments for invoking the update.
|
|
pub fn command_args(self) -> (&'static str, &'static [&'static str]) {
|
|
match self {
|
|
UpdateAction::NpmGlobalLatest => ("npm", &["install", "-g", "@openai/codex"]),
|
|
UpdateAction::BunGlobalLatest => ("bun", &["install", "-g", "@openai/codex"]),
|
|
UpdateAction::BrewUpgrade => ("brew", &["upgrade", "--cask", "codex"]),
|
|
UpdateAction::StandaloneUnix => (
|
|
"sh",
|
|
&[
|
|
"-c",
|
|
"curl -fsSL https://chatgpt.com/codex/install.sh | CODEX_NON_INTERACTIVE=1 sh",
|
|
],
|
|
),
|
|
UpdateAction::StandaloneWindows => (
|
|
"powershell",
|
|
&[
|
|
"-ExecutionPolicy",
|
|
"Bypass",
|
|
"-c",
|
|
"$env:CODEX_NON_INTERACTIVE=1; irm https://chatgpt.com/codex/install.ps1 | iex",
|
|
],
|
|
),
|
|
}
|
|
}
|
|
|
|
/// Returns string representation of the command-line arguments for invoking the update.
|
|
pub fn command_str(self) -> String {
|
|
let (command, args) = self.command_args();
|
|
shlex::try_join(std::iter::once(command).chain(args.iter().copied()))
|
|
.unwrap_or_else(|_| format!("{command} {}", args.join(" ")))
|
|
}
|
|
}
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
pub fn get_update_action() -> Option<UpdateAction> {
|
|
UpdateAction::from_install_context(InstallContext::current())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
|
use pretty_assertions::assert_eq;
|
|
|
|
#[test]
|
|
fn maps_install_context_to_update_action() {
|
|
let native_release_dir =
|
|
AbsolutePathBuf::from_absolute_path(std::env::temp_dir().join("native-release"))
|
|
.expect("temp dir path should be absolute");
|
|
|
|
assert_eq!(
|
|
UpdateAction::from_install_context(&InstallContext {
|
|
method: InstallMethod::Other,
|
|
package_layout: None,
|
|
}),
|
|
None
|
|
);
|
|
assert_eq!(
|
|
UpdateAction::from_install_context(&InstallContext {
|
|
method: InstallMethod::Npm,
|
|
package_layout: None,
|
|
}),
|
|
Some(UpdateAction::NpmGlobalLatest)
|
|
);
|
|
assert_eq!(
|
|
UpdateAction::from_install_context(&InstallContext {
|
|
method: InstallMethod::Bun,
|
|
package_layout: None,
|
|
}),
|
|
Some(UpdateAction::BunGlobalLatest)
|
|
);
|
|
assert_eq!(
|
|
UpdateAction::from_install_context(&InstallContext {
|
|
method: InstallMethod::Brew,
|
|
package_layout: None,
|
|
}),
|
|
Some(UpdateAction::BrewUpgrade)
|
|
);
|
|
assert_eq!(
|
|
UpdateAction::from_install_context(&InstallContext {
|
|
method: InstallMethod::Standalone {
|
|
platform: StandalonePlatform::Unix,
|
|
release_dir: native_release_dir.clone(),
|
|
resources_dir: Some(native_release_dir.join("codex-resources")),
|
|
},
|
|
package_layout: None,
|
|
}),
|
|
Some(UpdateAction::StandaloneUnix)
|
|
);
|
|
assert_eq!(
|
|
UpdateAction::from_install_context(&InstallContext {
|
|
method: InstallMethod::Standalone {
|
|
platform: StandalonePlatform::Windows,
|
|
release_dir: native_release_dir.clone(),
|
|
resources_dir: Some(native_release_dir.join("codex-resources")),
|
|
},
|
|
package_layout: None,
|
|
}),
|
|
Some(UpdateAction::StandaloneWindows)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn standalone_update_commands_rerun_latest_installer() {
|
|
assert_eq!(
|
|
UpdateAction::StandaloneUnix.command_args(),
|
|
(
|
|
"sh",
|
|
&[
|
|
"-c",
|
|
"curl -fsSL https://chatgpt.com/codex/install.sh | CODEX_NON_INTERACTIVE=1 sh"
|
|
][..],
|
|
)
|
|
);
|
|
assert_eq!(
|
|
UpdateAction::StandaloneWindows.command_args(),
|
|
(
|
|
"powershell",
|
|
&[
|
|
"-ExecutionPolicy",
|
|
"Bypass",
|
|
"-c",
|
|
"$env:CODEX_NON_INTERACTIVE=1; irm https://chatgpt.com/codex/install.ps1 | iex"
|
|
][..],
|
|
)
|
|
);
|
|
}
|
|
}
|