mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Auto-upgrade configured marketplaces (#17425)
## Summary - Add best-effort auto-upgrade for user-configured Git marketplaces recorded in `config.toml`. - Track the last activated Git revision with `last_revision` so unchanged marketplace sources skip clone work. - Trigger the upgrade from plugin startup and `plugin/list`, while preserving existing fail-open plugin behavior with warning logs rather than new user-visible errors. ## Details - Remote configured marketplaces use `git ls-remote` to compare the source/ref against the recorded revision. - Upgrades clone into a staging directory, validate that `.agents/plugins/marketplace.json` exists and that the manifest name matches the configured marketplace key, then atomically activate the new root. - Local `.agents/plugins/marketplace.json` marketplaces remain live filesystem state and are not auto-pulled. - Existing non-curated plugin cache refresh is kicked after successful marketplace root upgrades. ## Validation - `just write-config-schema` - `cargo test -p codex-core marketplace_upgrade` - `cargo check -p codex-cli -p codex-app-server` - `just fix -p codex-core` Did not run the complete `cargo test` suite because the repo instructions require asking before a full core workspace run.
This commit is contained in:
committed by
GitHub
Unverified
parent
109b22a8d0
commit
faf48489f3
@@ -1,8 +1,12 @@
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use anyhow::bail;
|
||||
use clap::Parser;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::config::find_codex_home;
|
||||
use codex_core::plugins::MarketplaceAddRequest;
|
||||
use codex_core::plugins::PluginMarketplaceUpgradeOutcome;
|
||||
use codex_core::plugins::PluginsManager;
|
||||
use codex_core::plugins::add_marketplace;
|
||||
use codex_utils_cli::CliConfigOverrides;
|
||||
|
||||
@@ -17,8 +21,8 @@ pub struct MarketplaceCli {
|
||||
|
||||
#[derive(Debug, clap::Subcommand)]
|
||||
enum MarketplaceSubcommand {
|
||||
/// Add a remote marketplace repository.
|
||||
Add(AddMarketplaceArgs),
|
||||
Upgrade(UpgradeMarketplaceArgs),
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
@@ -27,11 +31,9 @@ struct AddMarketplaceArgs {
|
||||
/// or local marketplace root directories.
|
||||
source: String,
|
||||
|
||||
/// Git ref to check out. Overrides any @ref or #ref suffix in SOURCE.
|
||||
#[arg(long = "ref", value_name = "REF")]
|
||||
ref_name: Option<String>,
|
||||
|
||||
/// Sparse-checkout path to use while cloning git sources. Repeat to include multiple paths.
|
||||
#[arg(
|
||||
long = "sparse",
|
||||
value_name = "PATH",
|
||||
@@ -40,6 +42,11 @@ struct AddMarketplaceArgs {
|
||||
sparse_paths: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct UpgradeMarketplaceArgs {
|
||||
marketplace_name: Option<String>,
|
||||
}
|
||||
|
||||
impl MarketplaceCli {
|
||||
pub async fn run(self) -> Result<()> {
|
||||
let MarketplaceCli {
|
||||
@@ -47,14 +54,13 @@ impl MarketplaceCli {
|
||||
subcommand,
|
||||
} = self;
|
||||
|
||||
// Validate overrides now. This command writes to CODEX_HOME only; marketplace discovery
|
||||
// happens from that cache root after the next plugin/list or app-server start.
|
||||
config_overrides
|
||||
let overrides = config_overrides
|
||||
.parse_overrides()
|
||||
.map_err(anyhow::Error::msg)?;
|
||||
|
||||
match subcommand {
|
||||
MarketplaceSubcommand::Add(args) => run_add(args).await?,
|
||||
MarketplaceSubcommand::Upgrade(args) => run_upgrade(overrides, args).await?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -98,6 +104,60 @@ async fn run_add(args: AddMarketplaceArgs) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn run_upgrade(
|
||||
overrides: Vec<(String, toml::Value)>,
|
||||
args: UpgradeMarketplaceArgs,
|
||||
) -> Result<()> {
|
||||
let UpgradeMarketplaceArgs { marketplace_name } = args;
|
||||
let config = Config::load_with_cli_overrides(overrides)
|
||||
.await
|
||||
.context("failed to load configuration")?;
|
||||
let codex_home = find_codex_home().context("failed to resolve CODEX_HOME")?;
|
||||
let manager = PluginsManager::new(codex_home.to_path_buf());
|
||||
let outcome = manager
|
||||
.upgrade_configured_marketplaces_for_config(&config, marketplace_name.as_deref())
|
||||
.map_err(anyhow::Error::msg)?;
|
||||
print_upgrade_outcome(&outcome, marketplace_name.as_deref())
|
||||
}
|
||||
|
||||
fn print_upgrade_outcome(
|
||||
outcome: &PluginMarketplaceUpgradeOutcome,
|
||||
marketplace_name: Option<&str>,
|
||||
) -> Result<()> {
|
||||
for error in &outcome.errors {
|
||||
eprintln!(
|
||||
"Failed to upgrade marketplace `{}`: {}",
|
||||
error.marketplace_name, error.message
|
||||
);
|
||||
}
|
||||
if !outcome.all_succeeded() {
|
||||
bail!("{} upgrade failure(s) occurred.", outcome.errors.len());
|
||||
}
|
||||
|
||||
let selection_label = marketplace_name.unwrap_or("all configured Git marketplaces");
|
||||
if outcome.selected_marketplaces.is_empty() {
|
||||
println!("No configured Git marketplaces to upgrade.");
|
||||
} else if outcome.upgraded_roots.is_empty() {
|
||||
if marketplace_name.is_some() {
|
||||
println!("Marketplace `{selection_label}` is already up to date.");
|
||||
} else {
|
||||
println!("All configured Git marketplaces are already up to date.");
|
||||
}
|
||||
} else if marketplace_name.is_some() {
|
||||
println!("Upgraded marketplace `{selection_label}` to the latest configured revision.");
|
||||
for root in &outcome.upgraded_roots {
|
||||
println!("Installed marketplace root: {}", root.display());
|
||||
}
|
||||
} else {
|
||||
println!("Upgraded {} marketplace(s).", outcome.upgraded_roots.len());
|
||||
for root in &outcome.upgraded_roots {
|
||||
println!("Installed marketplace root: {}", root.display());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -132,4 +192,13 @@ mod tests {
|
||||
vec!["plugins/foo", "skills/bar"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn upgrade_subcommand_parses_optional_marketplace_name() {
|
||||
let upgrade_all = UpgradeMarketplaceArgs::try_parse_from(["upgrade"]).unwrap();
|
||||
assert_eq!(upgrade_all.marketplace_name, None);
|
||||
|
||||
let upgrade_one = UpgradeMarketplaceArgs::try_parse_from(["upgrade", "debug"]).unwrap();
|
||||
assert_eq!(upgrade_one.marketplace_name.as_deref(), Some("debug"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user