mirror of
https://github.com/openai/codex.git
synced 2026-11-06 20:20:34 +00:00
add ci check for generated python
This commit is contained in:
@@ -65,6 +65,26 @@ jobs:
|
||||
- name: cargo fmt
|
||||
run: cargo fmt -- --config imports_granularity=Item --check
|
||||
|
||||
schema_fixtures:
|
||||
name: App-server schema fixtures
|
||||
runs-on: ubuntu-24.04
|
||||
needs: changed
|
||||
if: ${{ needs.changed.outputs.codex == 'true' || needs.changed.outputs.workflows == 'true' || github.event_name == 'push' }}
|
||||
defaults:
|
||||
run:
|
||||
working-directory: codex-rs
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- uses: astral-sh/setup-uv@v6
|
||||
- uses: dtolnay/rust-toolchain@1.93.0
|
||||
- name: Regenerate app-server schema fixtures
|
||||
run: cargo run -p codex-app-server-protocol --bin write_schema_fixtures
|
||||
- name: Check vendored schema fixtures are up to date
|
||||
run: git diff --exit-code -- app-server-protocol/schema
|
||||
|
||||
cargo_shear:
|
||||
name: cargo shear
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -200,6 +220,10 @@ jobs:
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
components: clippy
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- uses: astral-sh/setup-uv@v6
|
||||
|
||||
- if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl'}}
|
||||
name: Use hermetic Cargo home (musl)
|
||||
|
||||
@@ -141,6 +141,7 @@ class AskForApproval1(StrEnum):
|
||||
|
||||
class Reject(BaseModel):
|
||||
mcp_elicitations: bool
|
||||
request_permissions: bool
|
||||
rules: bool
|
||||
sandbox_approval: bool
|
||||
|
||||
@@ -324,6 +325,12 @@ class PluginInstallClientRequestMethod(RootModel[Literal["plugin/install"]]):
|
||||
)
|
||||
|
||||
|
||||
class PluginUninstallClientRequestMethod(RootModel[Literal["plugin/uninstall"]]):
|
||||
root: Literal["plugin/uninstall"] = Field(
|
||||
..., title="Plugin/uninstallClientRequestMethod"
|
||||
)
|
||||
|
||||
|
||||
class TurnStartClientRequestMethod(RootModel[Literal["turn/start"]]):
|
||||
root: Literal["turn/start"] = Field(..., title="Turn/startClientRequestMethod")
|
||||
|
||||
@@ -2378,6 +2385,11 @@ class PatchChangeKind(
|
||||
root: AddPatchChangeKind | DeletePatchChangeKind | UpdatePatchChangeKind
|
||||
|
||||
|
||||
class PermissionGrantScope(StrEnum):
|
||||
turn = "turn"
|
||||
session = "session"
|
||||
|
||||
|
||||
class PermissionProfile(BaseModel):
|
||||
file_system: FileSystemPermissions | None = None
|
||||
macos: MacOsSeatbeltProfileExtensions | None = None
|
||||
@@ -2421,6 +2433,10 @@ class PluginListParams(BaseModel):
|
||||
)
|
||||
|
||||
|
||||
class PluginUninstallParams(BaseModel):
|
||||
plugin_id: str = Field(..., alias="pluginId")
|
||||
|
||||
|
||||
class ProductSurface(StrEnum):
|
||||
chatgpt = "chatgpt"
|
||||
codex = "codex"
|
||||
@@ -2625,6 +2641,10 @@ class ReasoningTextDeltaNotification(BaseModel):
|
||||
|
||||
class RejectConfig(BaseModel):
|
||||
mcp_elicitations: bool = Field(..., description="Reject MCP elicitation prompts.")
|
||||
request_permissions: bool = Field(
|
||||
...,
|
||||
description="Reject approval prompts related to built-in permission requests.",
|
||||
)
|
||||
rules: bool = Field(
|
||||
..., description="Reject prompts triggered by execpolicy `prompt` rules."
|
||||
)
|
||||
@@ -4699,6 +4719,14 @@ class PluginInstallClientRequest(BaseModel):
|
||||
params: PluginInstallParams
|
||||
|
||||
|
||||
class PluginUninstallClientRequest(BaseModel):
|
||||
id: RequestId
|
||||
method: PluginUninstallClientRequestMethod = Field(
|
||||
..., title="Plugin/uninstallClientRequestMethod"
|
||||
)
|
||||
params: PluginUninstallParams
|
||||
|
||||
|
||||
class TurnInterruptClientRequest(BaseModel):
|
||||
id: RequestId
|
||||
method: TurnInterruptClientRequestMethod = Field(
|
||||
@@ -5686,6 +5714,7 @@ class PermissionsRequestApprovalParams(BaseModel):
|
||||
|
||||
class PermissionsRequestApprovalResponse(BaseModel):
|
||||
permissions: GrantedPermissionProfile
|
||||
scope: PermissionGrantScope | None = "turn"
|
||||
|
||||
|
||||
class PlanItemArg(BaseModel):
|
||||
@@ -6972,6 +7001,7 @@ class ClientRequest(
|
||||
| AppListClientRequest
|
||||
| SkillsConfigWriteClientRequest
|
||||
| PluginInstallClientRequest
|
||||
| PluginUninstallClientRequest
|
||||
| TurnStartClientRequest
|
||||
| TurnSteerClientRequest
|
||||
| TurnInterruptClientRequest
|
||||
@@ -7023,6 +7053,7 @@ class ClientRequest(
|
||||
| AppListClientRequest
|
||||
| SkillsConfigWriteClientRequest
|
||||
| PluginInstallClientRequest
|
||||
| PluginUninstallClientRequest
|
||||
| TurnStartClientRequest
|
||||
| TurnSteerClientRequest
|
||||
| TurnInterruptClientRequest
|
||||
|
||||
@@ -179,6 +179,7 @@ class AskForApproval1(StrEnum):
|
||||
|
||||
class Reject(BaseModel):
|
||||
mcp_elicitations: bool
|
||||
request_permissions: bool
|
||||
rules: bool
|
||||
sandbox_approval: bool
|
||||
|
||||
@@ -341,6 +342,12 @@ class PluginInstallClientRequestMethod(RootModel[Literal["plugin/install"]]):
|
||||
)
|
||||
|
||||
|
||||
class PluginUninstallClientRequestMethod(RootModel[Literal["plugin/uninstall"]]):
|
||||
root: Literal["plugin/uninstall"] = Field(
|
||||
..., title="Plugin/uninstallClientRequestMethod"
|
||||
)
|
||||
|
||||
|
||||
class TurnStartClientRequestMethod(RootModel[Literal["turn/start"]]):
|
||||
root: Literal["turn/start"] = Field(..., title="Turn/startClientRequestMethod")
|
||||
|
||||
@@ -2535,6 +2542,14 @@ class PluginSummary(BaseModel):
|
||||
source: PluginSource
|
||||
|
||||
|
||||
class PluginUninstallParams(BaseModel):
|
||||
plugin_id: str = Field(..., alias="pluginId")
|
||||
|
||||
|
||||
class PluginUninstallResponse(BaseModel):
|
||||
pass
|
||||
|
||||
|
||||
class ProductSurface(StrEnum):
|
||||
chatgpt = "chatgpt"
|
||||
codex = "codex"
|
||||
@@ -4796,6 +4811,14 @@ class PluginInstallClientRequest(BaseModel):
|
||||
params: PluginInstallParams
|
||||
|
||||
|
||||
class PluginUninstallClientRequest(BaseModel):
|
||||
id: RequestId
|
||||
method: PluginUninstallClientRequestMethod = Field(
|
||||
..., title="Plugin/uninstallClientRequestMethod"
|
||||
)
|
||||
params: PluginUninstallParams
|
||||
|
||||
|
||||
class TurnInterruptClientRequest(BaseModel):
|
||||
id: RequestId
|
||||
method: TurnInterruptClientRequestMethod = Field(
|
||||
@@ -6994,6 +7017,7 @@ class ClientRequest(
|
||||
| AppListClientRequest
|
||||
| SkillsConfigWriteClientRequest
|
||||
| PluginInstallClientRequest
|
||||
| PluginUninstallClientRequest
|
||||
| TurnStartClientRequest
|
||||
| TurnSteerClientRequest
|
||||
| TurnInterruptClientRequest
|
||||
@@ -7045,6 +7069,7 @@ class ClientRequest(
|
||||
| AppListClientRequest
|
||||
| SkillsConfigWriteClientRequest
|
||||
| PluginInstallClientRequest
|
||||
| PluginUninstallClientRequest
|
||||
| TurnStartClientRequest
|
||||
| TurnSteerClientRequest
|
||||
| TurnInterruptClientRequest
|
||||
|
||||
@@ -334,7 +334,7 @@ pub fn generate_python_with_options(
|
||||
}
|
||||
|
||||
fn generate_python_models(schema_path: &Path, output_path: &Path) -> Result<()> {
|
||||
let mut command = datamodel_codegen_command();
|
||||
let mut command = datamodel_codegen_command()?;
|
||||
command
|
||||
.arg("--input")
|
||||
.arg(schema_path)
|
||||
@@ -370,7 +370,7 @@ fn generate_python_models(schema_path: &Path, output_path: &Path) -> Result<()>
|
||||
if !status.success() {
|
||||
return Err(anyhow!(
|
||||
"Python model generator failed with status {status}. \
|
||||
Install `uv`/`uvx` or `datamodel-codegen` to regenerate app-server Python bindings."
|
||||
Install `uv` to run the vendored Python codegen toolchain."
|
||||
));
|
||||
}
|
||||
|
||||
@@ -385,33 +385,28 @@ Install `uv`/`uvx` or `datamodel-codegen` to regenerate app-server Python bindin
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn datamodel_codegen_command() -> Command {
|
||||
if command_exists("uv") {
|
||||
// Keep the uv-managed tool environment next to the protocol crate source,
|
||||
// not under schema/python/, which is regenerated as a fixture artifact.
|
||||
let python_codegen_project = Path::new(env!("CARGO_MANIFEST_DIR")).join("python");
|
||||
let mut command = Command::new("uv");
|
||||
command
|
||||
.arg("run")
|
||||
.arg("--project")
|
||||
.arg(python_codegen_project)
|
||||
.arg("--locked")
|
||||
.arg("python")
|
||||
.arg("-m")
|
||||
.arg("datamodel_code_generator");
|
||||
return command;
|
||||
fn datamodel_codegen_command() -> Result<Command> {
|
||||
// Keep the uv-managed tool environment next to the protocol crate source,
|
||||
// not under schema/python/, which is regenerated as a fixture artifact.
|
||||
let python_codegen_project = Path::new(env!("CARGO_MANIFEST_DIR")).join("python");
|
||||
if !uv_exists() {
|
||||
return Err(anyhow!(
|
||||
"Python model generation requires `uv` to be installed so the vendored \
|
||||
Python codegen toolchain can run from {}.",
|
||||
python_codegen_project.display()
|
||||
));
|
||||
}
|
||||
|
||||
if command_exists("uvx") {
|
||||
let mut command = Command::new("uvx");
|
||||
command
|
||||
.arg("--from")
|
||||
.arg("datamodel-code-generator")
|
||||
.arg("datamodel-codegen");
|
||||
return command;
|
||||
}
|
||||
|
||||
Command::new("datamodel-codegen")
|
||||
let mut command = Command::new("uv");
|
||||
command
|
||||
.arg("run")
|
||||
.arg("--project")
|
||||
.arg(python_codegen_project)
|
||||
.arg("--locked")
|
||||
.arg("python")
|
||||
.arg("-m")
|
||||
.arg("datamodel_code_generator");
|
||||
Ok(command)
|
||||
}
|
||||
|
||||
fn run_ruff_on_python_files(ruff: Option<&Path>, out_dir: &Path) -> Result<()> {
|
||||
@@ -438,39 +433,36 @@ fn ruff_command(ruff: Option<&Path>) -> Result<Command> {
|
||||
return Ok(Command::new(ruff_bin));
|
||||
}
|
||||
|
||||
if command_exists("uv") {
|
||||
let python_codegen_project = Path::new(env!("CARGO_MANIFEST_DIR")).join("python");
|
||||
let mut command = Command::new("uv");
|
||||
command
|
||||
.arg("run")
|
||||
.arg("--project")
|
||||
.arg(python_codegen_project)
|
||||
.arg("--locked")
|
||||
.arg("ruff");
|
||||
return Ok(command);
|
||||
let python_codegen_project = Path::new(env!("CARGO_MANIFEST_DIR")).join("python");
|
||||
if !uv_exists() {
|
||||
return Err(anyhow!(
|
||||
"Ruff formatting requires `uv` to be installed so the vendored Python \
|
||||
codegen toolchain can run from {}, or pass `--ruff /path/to/ruff`.",
|
||||
python_codegen_project.display()
|
||||
));
|
||||
}
|
||||
|
||||
if command_exists("ruff") {
|
||||
return Ok(Command::new("ruff"));
|
||||
}
|
||||
|
||||
Err(anyhow!(
|
||||
"Ruff was requested for Python generation, but no Ruff command is available. \
|
||||
Install `uv` for the vendored Python toolchain or pass `--ruff /path/to/ruff`."
|
||||
))
|
||||
let mut command = Command::new("uv");
|
||||
command
|
||||
.arg("run")
|
||||
.arg("--project")
|
||||
.arg(python_codegen_project)
|
||||
.arg("--locked")
|
||||
.arg("ruff");
|
||||
Ok(command)
|
||||
}
|
||||
|
||||
fn command_exists(command: &str) -> bool {
|
||||
fn uv_exists() -> bool {
|
||||
std::env::var_os("PATH").is_some_and(|paths| {
|
||||
std::env::split_paths(&paths).any(|path| {
|
||||
let candidate = path.join(command);
|
||||
let candidate = path.join("uv");
|
||||
if candidate.is_file() {
|
||||
return true;
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let candidate = path.join(format!("{command}.exe"));
|
||||
let candidate = path.join("uv.exe");
|
||||
candidate.is_file()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user