-
Notifications
You must be signed in to change notification settings - Fork 349
feat: add GOOGLE_WORKSPACE_CLI_API_BASE_URL for custom/mock endpoint support #100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@googleworkspace/cli": minor | ||
| --- | ||
|
|
||
| Add `GOOGLE_WORKSPACE_CLI_API_BASE_URL` env var to redirect API requests to a custom endpoint (e.g., mock server). Authentication is automatically skipped when set. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -183,6 +183,21 @@ pub struct JsonSchemaProperty { | |
| pub additional_properties: Option<Box<JsonSchemaProperty>>, | ||
| } | ||
|
|
||
| static CUSTOM_API_BASE_URL: std::sync::LazyLock<Option<String>> = std::sync::LazyLock::new(|| { | ||
| let url = std::env::var("GOOGLE_WORKSPACE_CLI_API_BASE_URL") | ||
| .ok() | ||
| .filter(|s| !s.is_empty()); | ||
| if let Some(ref u) = url { | ||
| eprintln!("[gws] Custom API endpoint active: {u}"); | ||
| eprintln!("[gws] Authentication is disabled. Requests will NOT go to Google APIs."); | ||
| } | ||
| url | ||
| }); | ||
|
|
||
| pub fn custom_api_base_url() -> Option<&'static str> { | ||
| CUSTOM_API_BASE_URL.as_deref() | ||
| } | ||
|
|
||
| /// Fetches and caches a Google Discovery Document. | ||
| pub async fn fetch_discovery_document( | ||
| service: &str, | ||
|
|
@@ -209,7 +224,8 @@ pub async fn fetch_discovery_document( | |
| if let Ok(modified) = metadata.modified() { | ||
| if modified.elapsed().unwrap_or_default() < std::time::Duration::from_secs(86400) { | ||
| let data = std::fs::read_to_string(&cache_file)?; | ||
| let doc: RestDescription = serde_json::from_str(&data)?; | ||
| let mut doc: RestDescription = serde_json::from_str(&data)?; | ||
| apply_base_url_override(&mut doc); | ||
| return Ok(doc); | ||
| } | ||
| } | ||
|
|
@@ -250,10 +266,27 @@ pub async fn fetch_discovery_document( | |
| let _ = e; | ||
| } | ||
|
|
||
| let doc: RestDescription = serde_json::from_str(&body)?; | ||
| let mut doc: RestDescription = serde_json::from_str(&body)?; | ||
| apply_base_url_override(&mut doc); | ||
| Ok(doc) | ||
| } | ||
|
|
||
| fn apply_base_url_override(doc: &mut RestDescription) { | ||
| if let Some(base) = custom_api_base_url() { | ||
| rewrite_base_url(doc, base); | ||
| } | ||
| } | ||
|
|
||
| fn rewrite_base_url(doc: &mut RestDescription, base: &str) { | ||
| let base_trimmed = base.trim_end_matches('/'); | ||
| let new_root_url = format!("{base_trimmed}/"); | ||
| let original_root_url = std::mem::replace(&mut doc.root_url, new_root_url); | ||
|
|
||
| if let Some(base_url) = &mut doc.base_url { | ||
| *base_url = base_url.replace(&original_root_url, &doc.root_url); | ||
| } | ||
| } | ||
|
Comment on lines
+280
to
+288
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current implementation of For example, a request to The fix is to replace only the host part of the fn rewrite_base_url(doc: &mut RestDescription, base: &str) {
let base_trimmed = base.trim_end_matches('/');
let new_root_url = format!("{base_trimmed}/");
let original_root_url = std::mem::replace(&mut doc.root_url, new_root_url);
if let Some(base_url) = &mut doc.base_url {
*base_url = base_url.replace(&original_root_url, &doc.root_url);
}
} |
||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
@@ -323,4 +356,55 @@ mod tests { | |
| assert!(doc.resources.is_empty()); | ||
| assert!(doc.schemas.is_empty()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_rewrite_base_url_empty_service_path() { | ||
| let mut doc = RestDescription { | ||
| name: "gmail".to_string(), | ||
| version: "v1".to_string(), | ||
| root_url: "https://gmail.googleapis.com/".to_string(), | ||
| base_url: Some("https://gmail.googleapis.com/".to_string()), | ||
| service_path: "".to_string(), | ||
| ..Default::default() | ||
| }; | ||
|
|
||
| rewrite_base_url(&mut doc, "http://localhost:8099"); | ||
| assert_eq!(doc.root_url, "http://localhost:8099/"); | ||
| assert_eq!(doc.base_url.as_deref(), Some("http://localhost:8099/")); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_rewrite_base_url_preserves_service_path() { | ||
| let mut doc = RestDescription { | ||
| name: "drive".to_string(), | ||
| version: "v3".to_string(), | ||
| root_url: "https://www.googleapis.com/".to_string(), | ||
| base_url: Some("https://www.googleapis.com/drive/v3/".to_string()), | ||
| service_path: "drive/v3/".to_string(), | ||
| ..Default::default() | ||
| }; | ||
|
|
||
| rewrite_base_url(&mut doc, "http://localhost:8099/"); | ||
| assert_eq!(doc.root_url, "http://localhost:8099/"); | ||
| assert_eq!( | ||
| doc.base_url.as_deref(), | ||
| Some("http://localhost:8099/drive/v3/") | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_rewrite_base_url_none() { | ||
| let mut doc = RestDescription { | ||
| name: "customsearch".to_string(), | ||
| version: "v1".to_string(), | ||
| root_url: "https://www.googleapis.com/".to_string(), | ||
| base_url: None, | ||
| service_path: "customsearch/v1/".to_string(), | ||
| ..Default::default() | ||
| }; | ||
|
|
||
| rewrite_base_url(&mut doc, "http://localhost:8099"); | ||
| assert_eq!(doc.root_url, "http://localhost:8099/"); | ||
| assert!(doc.base_url.is_none()); | ||
| } | ||
|
Comment on lines
+360
to
+409
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These tests need to be updated to reflect the correct behavior of #[test]
fn test_rewrite_base_url() {
let mut doc = RestDescription {
name: "gmail".to_string(),
version: "v1".to_string(),
root_url: "https://gmail.googleapis.com/".to_string(),
base_url: Some("https://gmail.googleapis.com/gmail/v1/".to_string()),
service_path: "gmail/v1/".to_string(),
..Default::default()
};
rewrite_base_url(&mut doc, "http://localhost:8099");
assert_eq!(doc.root_url, "http://localhost:8099/");
assert_eq!(
doc.base_url.as_deref(),
Some("http://localhost:8099/gmail/v1/")
);
}
#[test]
fn test_rewrite_base_url_trailing_slash() {
let mut doc = RestDescription {
name: "drive".to_string(),
version: "v3".to_string(),
root_url: "https://www.googleapis.com/".to_string(),
base_url: Some("https://www.googleapis.com/drive/v3/".to_string()),
..Default::default()
};
rewrite_base_url(&mut doc, "http://localhost:8099/");
assert_eq!(doc.root_url, "http://localhost:8099/");
assert_eq!(
doc.base_url.as_deref(),
Some("http://localhost:8099/drive/v3/")
);
} |
||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.