Skip to content

Commit

Permalink
fix(mfe): avoid crashing if unsupported mfe version found (#9432)
Browse files Browse the repository at this point in the history
### Description

We should avoid crashing if we encounter a version of MFE config that we
don't currently support.

### Testing Instructions

Added unit test. Quick spot check by changing version in an example to
an unsupported version:

```
[1 olszewski@chriss-mbp] /Users/olszewski/code/ $ turbo_dev --skip-infer micro-frontends-example-web#dev --dry=json > /dev/null
turbo 2.2.4-canary.10

 WARNING  Ignoring /Users/olszewski/code/packages/micro-frontends-example-site-config/micro-frontends.jsonc: Unsupported micro-frontends configuration version: 2. Supported versions: ["1"]
```
  • Loading branch information
chris-olszewski authored Nov 13, 2024
1 parent 9a9fc93 commit 43ab1c7
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 4 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion crates/turborepo-lib/src/micro_frontends.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::{HashMap, HashSet};

use tracing::warn;
use turbopath::AbsoluteSystemPath;
use turborepo_micro_frontend::{Config as MFEConfig, Error, DEFAULT_MICRO_FRONTENDS_CONFIG};
use turborepo_repository::package_graph::PackageGraph;
Expand All @@ -21,7 +22,15 @@ impl MicroFrontendsConfigs {
let config_path = repo_root
.resolve(package_info.package_path())
.join_component(DEFAULT_MICRO_FRONTENDS_CONFIG);
let Some(config) = MFEConfig::load(&config_path)? else {
let Some(config) = MFEConfig::load(&config_path).or_else(|err| {
if matches!(err, turborepo_micro_frontend::Error::UnsupportedVersion(_)) {
warn!("Ignoring {config_path}: {err}");
Ok(None)
} else {
Err(err)
}
})?
else {
continue;
};
let tasks = config
Expand Down
1 change: 1 addition & 0 deletions crates/turborepo-micro-frontend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ turbopath = { workspace = true }
turborepo-errors = { workspace = true }

[dev-dependencies]
insta = { workspace = true }
pretty_assertions = { workspace = true }

[lints]
Expand Down
7 changes: 7 additions & 0 deletions crates/turborepo-micro-frontend/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
use turborepo_errors::ParseDiagnostic;

use crate::SUPPORTED_VERSIONS;

#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Unable to read configuration file: {0}")]
Io(#[from] std::io::Error),
#[error("Unable to parse JSON: {0}")]
JsonParse(String),
#[error(
"Unsupported micro-frontends configuration version: {0}. Supported versions: \
{SUPPORTED_VERSIONS:?}"
)]
UnsupportedVersion(String),
}

impl Error {
Expand Down
33 changes: 30 additions & 3 deletions crates/turborepo-micro-frontend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use turbopath::AbsoluteSystemPath;
pub const DEFAULT_MICRO_FRONTENDS_CONFIG: &str = "micro-frontends.jsonc";
pub const MICRO_FRONTENDS_PACKAGES: &[&str] = [MICRO_FRONTENDS_PACKAGE_INTERNAL].as_slice();
pub const MICRO_FRONTENDS_PACKAGE_INTERNAL: &str = "@vercel/micro-frontends-internal";
pub const SUPPORTED_VERSIONS: &[&str] = ["1"].as_slice();

/// The minimal amount of information Turborepo needs to correctly start a local
/// proxy server for microfrontends
Expand All @@ -31,11 +32,28 @@ impl Config {
let Some(contents) = config_path.read_existing_to_string()? else {
return Ok(None);
};
let config = Self::from_str(&contents, config_path.as_str()).map_err(Error::biome_error)?;
let config = Self::from_str(&contents, config_path.as_str())?;
Ok(Some(config))
}

pub fn from_str(input: &str, source: &str) -> Result<Self, Vec<biome_diagnostics::Error>> {
pub fn from_str(input: &str, source: &str) -> Result<Self, Error> {
#[derive(Deserializable, Default)]
struct VersionOnly {
version: String,
}
let (version_only, _errs) = biome_deserialize::json::deserialize_from_json_str(
input,
JsonParserOptions::default().with_allow_comments(),
source,
)
.consume();
// If parsing just the version fails, fallback to full schema to provide better
// error message
if let Some(VersionOnly { version }) = version_only {
if !SUPPORTED_VERSIONS.contains(&version.as_str()) {
return Err(Error::UnsupportedVersion(version));
}
}
let (config, errs) = biome_deserialize::json::deserialize_from_json_str(
input,
JsonParserOptions::default().with_allow_comments(),
Expand All @@ -45,7 +63,7 @@ impl Config {
if let Some(config) = config {
Ok(config)
} else {
Err(errs)
Err(Error::biome_error(errs))
}
}
}
Expand All @@ -63,6 +81,8 @@ pub struct Development {

#[cfg(test)]
mod test {
use insta::assert_snapshot;

use super::*;

#[test]
Expand All @@ -71,4 +91,11 @@ mod test {
let example_config = Config::from_str(input, "something.json");
assert!(example_config.is_ok());
}

#[test]
fn test_unsupported_version() {
let input = r#"{"version": "yolo"}"#;
let err = Config::from_str(input, "something.json").unwrap_err();
assert_snapshot!(err, @r###"Unsupported micro-frontends configuration version: yolo. Supported versions: ["1"]"###);
}
}

0 comments on commit 43ab1c7

Please sign in to comment.