extension_cli: Ensure extension that provide themes do not provide further features (#52272)

Finn Evers created

We generally enforce this policy already and also want this to be this
way, so better to be error than sorry here.

Release Notes:

- N/A

Change summary

crates/extension_cli/src/main.rs | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)

Detailed changes

crates/extension_cli/src/main.rs 🔗

@@ -1,3 +1,4 @@
+use std::collections::BTreeSet;
 use std::collections::HashMap;
 use std::env;
 use std::fs;
@@ -7,6 +8,7 @@ use std::sync::Arc;
 use ::fs::{CopyOptions, Fs, RealFs, copy_recursive};
 use anyhow::{Context as _, Result, anyhow, bail};
 use clap::Parser;
+use cloud_api_types::ExtensionProvides;
 use extension::extension_builder::{CompileExtensionOptions, ExtensionBuilder};
 use extension::{ExtensionManifest, ExtensionSnippets};
 use language::LanguageConfig;
@@ -80,10 +82,7 @@ async fn main() -> Result<()> {
         .context("failed to compile extension")?;
 
     let extension_provides = manifest.provides();
-
-    if extension_provides.is_empty() {
-        bail!("extension does not provide any features");
-    }
+    validate_extension_features(&extension_provides)?;
 
     let grammars = test_grammars(&manifest, &extension_path, &mut wasm_store)?;
     test_languages(&manifest, &extension_path, &grammars)?;
@@ -203,7 +202,7 @@ async fn copy_extension_resources(
             },
         )
         .await
-        .with_context(|| "failed to copy icons")?;
+        .context("failed to copy icons")?;
     }
 
     for (_, agent_entry) in &manifest.agent_servers {
@@ -297,6 +296,22 @@ async fn copy_extension_resources(
     Ok(())
 }
 
+fn validate_extension_features(provides: &BTreeSet<ExtensionProvides>) -> Result<()> {
+    if provides.is_empty() {
+        bail!("extension does not provide any features");
+    }
+
+    if provides.contains(&ExtensionProvides::Themes) && provides.len() != 1 {
+        bail!("extension must not provide other features along with themes");
+    }
+
+    if provides.contains(&ExtensionProvides::IconThemes) && provides.len() != 1 {
+        bail!("extension must not provide other features along with icon themes");
+    }
+
+    Ok(())
+}
+
 fn test_grammars(
     manifest: &ExtensionManifest,
     extension_path: &Path,