Compare commits

...

7 Commits

Author SHA1 Message Date
Micah
844f51d916 Update version of aftman used in release workflow 2024-07-23 11:14:18 -07:00
Micah
26974ffd4c Release v7.4.2 (#950) 2024-07-23 11:02:23 -07:00
Micah
91f5b4a675 Update memofs in 7.4.x branch (#949)
Backports the release of memofs v0.3.0
2024-07-23 10:42:32 -07:00
Micah
d179240139 Update rbx_dom for 7.4.x branch (#948) 2024-07-23 10:35:06 -07:00
Micah
67b6a7e198 Backport #917 to Rojo 7.4.x branch (#947) 2024-07-22 12:11:28 -07:00
Micah
3b721242c1 Backport #893 and #903 to Rojo 7.4 (#946)
As part of prep for a 7.4.2 release, this backports changes to the 7.4.X
branch that we can reasonably ship in 7.4.2 without too many code
changes.
2024-07-22 11:55:28 -07:00
EgoMoose
c6ceaa5c87 Trim plugin version string (#889)
This PR is a very small change that fixes the string pattern that reads
the rojo version from `Version.txt`. Currently this reads an extra
new-line character which makes reading the version text in the plugin
difficult.

It seems the rust side of things already trims the string when
comparing, but the lua side does not.

Current:

![pO6gtOXAZq](https://github.com/rojo-rbx/rojo/assets/6201941/1a03fced-f2b5-4a4e-a82d-e11fb0a52af7)

Fix:

![RobloxStudioBeta_GHmiJKAoa3](https://github.com/rojo-rbx/rojo/assets/6201941/3ce711df-fdc6-4f20-8771-5f5118ee013f)

Apologies if I skipped over some process of submitting a bug and / or am
basing on the wrong branch etc.
2024-03-13 09:49:33 -07:00
20 changed files with 3408 additions and 784 deletions

View File

@@ -36,7 +36,7 @@ jobs:
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
trust-check: false trust-check: false
version: 'v0.2.6' version: 'v0.3.0'
- name: Build Plugin - name: Build Plugin
run: rojo build plugin --output Rojo.rbxm run: rojo build plugin --output Rojo.rbxm

View File

@@ -2,6 +2,17 @@
## Unreleased Changes ## Unreleased Changes
## [7.4.2] - July 23, 2024
* Added Never option to Confirmation ([#893])
* Fixed removing trailing newlines ([#903])
* Updated the internal property database, correcting an issue with `SurfaceAppearance.Color` that was reported [here][Surface_Appearance_Color_1] and [here][Surface_Appearance_Color_2] ([#948])
[#893]: https://github.com/rojo-rbx/rojo/pull/893
[#903]: https://github.com/rojo-rbx/rojo/pull/903
[#948]: https://github.com/rojo-rbx/rojo/pull/948
[Surface_Appearance_Color_1]: https://devforum.roblox.com/t/jailbreak-custom-character-turned-shiny-black-no-texture/3075563
[Surface_Appearance_Color_2]: https://devforum.roblox.com/t/surfaceappearance-not-displaying-correctly/3075588
## [7.4.1] - February 20, 2024 ## [7.4.1] - February 20, 2024
* Made the `name` field optional on project files ([#870]) * Made the `name` field optional on project files ([#870])
Files named `default.project.json` inherit the name of the folder they're in and all other projects Files named `default.project.json` inherit the name of the folder they're in and all other projects

28
Cargo.lock generated
View File

@@ -1073,7 +1073,7 @@ dependencies = [
[[package]] [[package]]
name = "memofs" name = "memofs"
version = "0.2.0" version = "0.3.0"
dependencies = [ dependencies = [
"crossbeam-channel", "crossbeam-channel",
"fs-err", "fs-err",
@@ -1586,9 +1586,9 @@ dependencies = [
[[package]] [[package]]
name = "rbx_binary" name = "rbx_binary"
version = "0.7.4" version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6314dd6bf5c21d0598cdb53cf5d241aa643ba41da8b8abf7402b4a35096f03f6" checksum = "a7f03840a9fe103f124d1f71c86eb6e2c70e8c0db0454a0eb353db3c64d6de8e"
dependencies = [ dependencies = [
"log", "log",
"lz4", "lz4",
@@ -1601,9 +1601,9 @@ dependencies = [
[[package]] [[package]]
name = "rbx_dom_weak" name = "rbx_dom_weak"
version = "2.7.0" version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b67b56bac99849c2e3c57547b036927f71c57cf7f4d900d04e3e4ee774ec316" checksum = "34d35df0f09290d32976f655366342676a6645b87c39b6949473b9d28a969733"
dependencies = [ dependencies = [
"rbx_types", "rbx_types",
"serde", "serde",
@@ -1611,9 +1611,9 @@ dependencies = [
[[package]] [[package]]
name = "rbx_reflection" name = "rbx_reflection"
version = "4.5.0" version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d41509c991b53a7276a746a795eae2b9204f398164920f61976995b47fe1722" checksum = "04ca5496737668378b17bacc9090ad361fc9c8b5f346bbd33162e083c98fa248"
dependencies = [ dependencies = [
"rbx_types", "rbx_types",
"serde", "serde",
@@ -1622,9 +1622,9 @@ dependencies = [
[[package]] [[package]]
name = "rbx_reflection_database" name = "rbx_reflection_database"
version = "0.2.10+roblox-607" version = "0.2.11+roblox-634"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12e20c06fa41f7aadc79005c8354f592b2c2f4d0c61e1080ed5718dafc30aea0" checksum = "399ab2e1fa27c8428fe43fc4148d8085d187881f1c59cefea3711a2112e9cccc"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"rbx_reflection", "rbx_reflection",
@@ -1634,9 +1634,9 @@ dependencies = [
[[package]] [[package]]
name = "rbx_types" name = "rbx_types"
version = "1.8.0" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ca23bfd469d067d81ef14f65fe09aeddc25abcf576a889d1a7664fe021cf18c" checksum = "6ed7bbc0e1864143546b12ee0cf64a1a6f447d8ce7baf4fae755e4581929d230"
dependencies = [ dependencies = [
"base64 0.13.1", "base64 0.13.1",
"bitflags 1.3.2", "bitflags 1.3.2",
@@ -1649,9 +1649,9 @@ dependencies = [
[[package]] [[package]]
name = "rbx_xml" name = "rbx_xml"
version = "0.13.3" version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8c03f95500961c32340791d1fabd4587f6873bdbff077ecca6ae32db7960dea" checksum = "1c2abac6e71c97a56243f00c9c2def504fe4b698019d854dd8720da700a80d7c"
dependencies = [ dependencies = [
"base64 0.13.1", "base64 0.13.1",
"log", "log",
@@ -1831,7 +1831,7 @@ dependencies = [
[[package]] [[package]]
name = "rojo" name = "rojo"
version = "7.4.1" version = "7.4.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"backtrace", "backtrace",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "rojo" name = "rojo"
version = "7.4.1" version = "7.4.2"
rust-version = "1.70.0" rust-version = "1.70.0"
authors = ["Lucien Greathouse <me@lpghatguy.com>"] authors = ["Lucien Greathouse <me@lpghatguy.com>"]
description = "Enables professional-grade development tools for Roblox developers" description = "Enables professional-grade development tools for Roblox developers"
@@ -40,7 +40,7 @@ name = "build"
harness = false harness = false
[dependencies] [dependencies]
memofs = { version = "0.2.0", path = "crates/memofs" } memofs = { version = "0.3.0", path = "crates/memofs" }
# These dependencies can be uncommented when working on rbx-dom simultaneously # These dependencies can be uncommented when working on rbx-dom simultaneously
# rbx_binary = { path = "../rbx-dom/rbx_binary" } # rbx_binary = { path = "../rbx-dom/rbx_binary" }
@@ -49,11 +49,11 @@ memofs = { version = "0.2.0", path = "crates/memofs" }
# rbx_reflection_database = { path = "../rbx-dom/rbx_reflection_database" } # rbx_reflection_database = { path = "../rbx-dom/rbx_reflection_database" }
# rbx_xml = { path = "../rbx-dom/rbx_xml" } # rbx_xml = { path = "../rbx-dom/rbx_xml" }
rbx_binary = "0.7.4" rbx_binary = "0.7.5"
rbx_dom_weak = "2.7.0" rbx_dom_weak = "2.8.0"
rbx_reflection = "4.5.0" rbx_reflection = "4.6.0"
rbx_reflection_database = "0.2.10" rbx_reflection_database = "0.2.11"
rbx_xml = "0.13.3" rbx_xml = "0.13.4"
anyhow = "1.0.44" anyhow = "1.0.44"
backtrace = "0.3.61" backtrace = "0.3.61"
@@ -94,7 +94,7 @@ tracy-client = { version = "0.13.2", optional = true }
winreg = "0.10.1" winreg = "0.10.1"
[build-dependencies] [build-dependencies]
memofs = { version = "0.2.0", path = "crates/memofs" } memofs = { version = "0.3.0", path = "crates/memofs" }
embed-resource = "1.6.4" embed-resource = "1.6.4"
anyhow = "1.0.44" anyhow = "1.0.44"

View File

@@ -1,6 +1,8 @@
# memofs Changelog # memofs Changelog
## Unreleased Changes ## Unreleased Changes
## 0.3.0 (2024-03-15)
* Changed `StdBackend` file watching component to use minimal recursive watches. [#830] * Changed `StdBackend` file watching component to use minimal recursive watches. [#830]
* Added `Vfs::read_to_string` and `Vfs::read_to_string_lf_normalized` [#854] * Added `Vfs::read_to_string` and `Vfs::read_to_string_lf_normalized` [#854]

View File

@@ -1,7 +1,7 @@
[package] [package]
name = "memofs" name = "memofs"
description = "Virtual filesystem with configurable backends." description = "Virtual filesystem with configurable backends."
version = "0.2.0" version = "0.3.0"
authors = ["Lucien Greathouse <me@lpghatguy.com>"] authors = ["Lucien Greathouse <me@lpghatguy.com>"]
edition = "2018" edition = "2018"
readme = "README.md" readme = "README.md"

View File

@@ -300,7 +300,7 @@ impl Vfs {
let path = path.as_ref(); let path = path.as_ref();
let contents = self.inner.lock().unwrap().read_to_string(path)?; let contents = self.inner.lock().unwrap().read_to_string(path)?;
Ok(contents.lines().collect::<Vec<&str>>().join("\n").into()) Ok(contents.replace("\r\n", "\n").into())
} }
/// Write a file to the VFS and the underlying backend. /// Write a file to the VFS and the underlying backend.
@@ -473,3 +473,23 @@ impl VfsLock<'_> {
self.inner.commit_event(event) self.inner.commit_event(event)
} }
} }
#[cfg(test)]
mod test {
use crate::{InMemoryFs, Vfs, VfsSnapshot};
/// https://github.com/rojo-rbx/rojo/issues/899
#[test]
fn read_to_string_lf_normalized_keeps_trailing_newline() {
let mut imfs = InMemoryFs::new();
imfs.load_snapshot("test", VfsSnapshot::file("bar\r\nfoo\r\n\r\n"))
.unwrap();
let vfs = Vfs::new(imfs);
assert_eq!(
vfs.read_to_string_lf_normalized("test").unwrap().as_str(),
"bar\nfoo\n\n"
);
}
}

View File

@@ -1 +1 @@
7.4.1 7.4.2

View File

@@ -113,13 +113,14 @@ return {
}, },
WorldPivotData = { WorldPivotData = {
read = function(instance) read = function(instance)
return true, instance:GetPivot() return true, instance.WorldPivot
end, end,
write = function(instance, _, value) write = function(instance, _, value)
if value == nil then if value == nil then
return true, nil return true, nil
else else
return true, instance:PivotTo(value) instance.WorldPivot = value
return true
end end
end, end,
}, },

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@ local function invertTbl(tbl)
end end
local invertedLevels = invertTbl(Log.Level) local invertedLevels = invertTbl(Log.Level)
local confirmationBehaviors = { "Initial", "Always", "Large Changes", "Unlisted PlaceId" } local confirmationBehaviors = { "Initial", "Always", "Large Changes", "Unlisted PlaceId", "Never" }
local function Navbar(props) local function Navbar(props)
return Theme.with(function(theme) return Theme.with(function(theme)

View File

@@ -516,6 +516,9 @@ function App:startSession()
return "Accept" return "Accept"
end end
end end
elseif confirmationBehavior == "Never" then
Log.trace("Accepting patch without confirmation because behavior is set to Never")
return "Accept"
end end
-- The datamodel name gets overwritten by Studio, making confirmation of it intrusive -- The datamodel name gets overwritten by Studio, making confirmation of it intrusive

View File

@@ -3,7 +3,8 @@ local strict = require(script.Parent.strict)
local isDevBuild = script.Parent.Parent:FindFirstChild("ROJO_DEV_BUILD") ~= nil local isDevBuild = script.Parent.Parent:FindFirstChild("ROJO_DEV_BUILD") ~= nil
local Version = script.Parent.Parent.Version local Version = script.Parent.Parent.Version
local major, minor, patch, metadata = Version.Value:match("^(%d+)%.(%d+)%.(%d+)(.*)$") local trimmedVersionValue = Version.Value:gsub("^%s+", ""):gsub("%s+$", "")
local major, minor, patch, metadata = trimmedVersionValue:match("^(%d+)%.(%d+)%.(%d+)(.*)$")
local realVersion = { major, minor, patch, metadata } local realVersion = { major, minor, patch, metadata }
for i = 1, 3 do for i = 1, 3 do

View File

@@ -0,0 +1,19 @@
---
source: tests/tests/serve.rs
expression: "read_response.intern_and_redact(&mut redactions, root_id)"
---
instances:
id-2:
Children: []
ClassName: StringValue
Id: id-2
Metadata:
ignoreUnknownInstances: true
Name: no_name_top_level_project
Parent: "00000000000000000000000000000000"
Properties:
Value:
String: "If this isn't named `no_name_top_level_project`, something went wrong!"
messageCursor: 0
sessionId: id-1

View File

@@ -2,6 +2,7 @@ use std::path::PathBuf;
use anyhow::Context; use anyhow::Context;
use clap::Parser; use clap::Parser;
use memofs::Vfs;
use crate::project::Project; use crate::project::Project;
@@ -17,8 +18,11 @@ pub struct FmtProjectCommand {
impl FmtProjectCommand { impl FmtProjectCommand {
pub fn run(self) -> anyhow::Result<()> { pub fn run(self) -> anyhow::Result<()> {
let vfs = Vfs::new_default();
vfs.set_watch_enabled(false);
let base_path = resolve_path(&self.project); let base_path = resolve_path(&self.project);
let project = Project::load_fuzzy(&base_path)? let project = Project::load_fuzzy(&vfs, &base_path)?
.context("A project file is required to run 'rojo fmt-project'")?; .context("A project file is required to run 'rojo fmt-project'")?;
let serialized = serde_json::to_string_pretty(&project) let serialized = serde_json::to_string_pretty(&project)

View File

@@ -1,10 +1,12 @@
use std::{ use std::{
collections::{BTreeMap, HashMap, HashSet}, collections::{BTreeMap, HashMap, HashSet},
ffi::OsStr,
fs, io, fs, io,
net::IpAddr, net::IpAddr,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use memofs::Vfs;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
@@ -19,6 +21,14 @@ pub struct ProjectError(#[from] Error);
#[derive(Debug, Error)] #[derive(Debug, Error)]
enum Error { enum Error {
#[error("The folder for the provided project cannot be used as a project name: {}\n\
Consider setting the `name` field on this project.", .path.display())]
FolderNameInvalid { path: PathBuf },
#[error("The file name of the provided project cannot be used as a project name: {}.\n\
Consider setting the `name` field on this project.", .path.display())]
ProjectNameInvalid { path: PathBuf },
#[error(transparent)] #[error(transparent)]
Io { Io {
#[from] #[from]
@@ -129,43 +139,91 @@ impl Project {
} }
} }
pub fn load_from_slice( /// Sets the name of a project. The order it handles is as follows:
///
/// - If the project is a `default.project.json`, uses the folder's name
/// - If a fallback is specified, uses that blindly
/// - Otherwise, loops through sync rules (including the default ones!) and
/// uses the name of the first one that matches and is a project file
fn set_file_name(&mut self, fallback: Option<&str>) -> Result<(), Error> {
let file_name = self
.file_location
.file_name()
.and_then(OsStr::to_str)
.ok_or_else(|| Error::ProjectNameInvalid {
path: self.file_location.clone(),
})?;
// If you're editing this to be generic, make sure you also alter the
// snapshot middleware to support generic init paths.
if file_name == PROJECT_FILENAME {
let folder_name = self.folder_location().file_name().and_then(OsStr::to_str);
if let Some(folder_name) = folder_name {
self.name = Some(folder_name.to_string());
} else {
return Err(Error::FolderNameInvalid {
path: self.file_location.clone(),
});
}
} else if let Some(fallback) = fallback {
self.name = Some(fallback.to_string());
} else {
unimplemented!(
"7.4.X branch will hopefully never have a case where fallback isn't provided to set_file_name"
);
}
Ok(())
}
/// Loads a Project file from the provided contents with its source set as
/// the provided location.
fn load_from_slice(
contents: &[u8], contents: &[u8],
project_file_location: &Path, project_file_location: PathBuf,
) -> Result<Self, ProjectError> { fallback_name: Option<&str>,
) -> Result<Self, Error> {
let mut project: Self = serde_json::from_slice(contents).map_err(|source| Error::Json { let mut project: Self = serde_json::from_slice(contents).map_err(|source| Error::Json {
source, source,
path: project_file_location.to_owned(), path: project_file_location.clone(),
})?; })?;
project.file_location = project_file_location;
project.file_location = project_file_location.to_path_buf();
project.check_compatibility(); project.check_compatibility();
if project.name.is_none() {
project.set_file_name(fallback_name)?;
}
Ok(project) Ok(project)
} }
pub fn load_fuzzy(fuzzy_project_location: &Path) -> Result<Option<Self>, ProjectError> { /// Loads a Project from a path. This will find the project if it refers to
/// a `.project.json` file or if it refers to a directory that contains a
/// file named `default.project.json`.
pub fn load_fuzzy(
vfs: &Vfs,
fuzzy_project_location: &Path,
) -> Result<Option<Self>, ProjectError> {
if let Some(project_path) = Self::locate(fuzzy_project_location) { if let Some(project_path) = Self::locate(fuzzy_project_location) {
let project = Self::load_exact(&project_path)?; let contents = vfs.read(&project_path).map_err(Error::from)?;
Ok(Some(Self::load_from_slice(&contents, project_path, None)?))
Ok(Some(project))
} else { } else {
Ok(None) Ok(None)
} }
} }
fn load_exact(project_file_location: &Path) -> Result<Self, Error> { /// Loads a Project from a path.
let contents = fs::read_to_string(project_file_location)?; pub fn load_exact(
vfs: &Vfs,
let mut project: Project = project_file_location: &Path,
serde_json::from_str(&contents).map_err(|source| Error::Json { fallback_name: Option<&str>,
source, ) -> Result<Self, ProjectError> {
path: project_file_location.to_owned(), let project_path = project_file_location.to_path_buf();
})?; let contents = vfs.read(&project_path).map_err(Error::from)?;
Ok(Self::load_from_slice(
project.file_location = project_file_location.to_path_buf(); &contents,
project.check_compatibility(); project_path,
fallback_name,
Ok(project) )?)
} }
/// Checks if there are any compatibility issues with this project file and /// Checks if there are any compatibility issues with this project file and

View File

@@ -9,7 +9,6 @@ use std::{
}; };
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
use memofs::IoResultExt;
use memofs::Vfs; use memofs::Vfs;
use thiserror::Error; use thiserror::Error;
@@ -110,43 +109,14 @@ impl ServeSession {
log::debug!("Loading project file from {}", project_path.display()); log::debug!("Loading project file from {}", project_path.display());
let mut root_project = match vfs.read(&project_path).with_not_found()? { let root_project = match Project::load_exact(&vfs, &project_path, None) {
Some(contents) => Project::load_from_slice(&contents, &project_path)?, Ok(project) => project,
None => { Err(_) => {
return Err(ServeSessionError::NoProjectFound { return Err(ServeSessionError::NoProjectFound {
path: project_path.to_path_buf(), path: project_path.to_path_buf(),
}); });
} }
}; };
if root_project.name.is_none() {
if let Some(file_name) = project_path.file_name().and_then(|s| s.to_str()) {
if file_name == "default.project.json" {
let folder_name = project_path
.parent()
.and_then(Path::file_name)
.and_then(|s| s.to_str());
if let Some(folder_name) = folder_name {
root_project.name = Some(folder_name.to_string());
} else {
return Err(ServeSessionError::FolderNameInvalid {
path: project_path.to_path_buf(),
});
}
} else if let Some(trimmed) = file_name.strip_suffix(".project.json") {
root_project.name = Some(trimmed.to_string());
} else {
return Err(ServeSessionError::ProjectNameInvalid {
path: project_path.to_path_buf(),
});
}
} else {
return Err(ServeSessionError::ProjectNameInvalid {
path: project_path.to_path_buf(),
});
}
}
// Rebind it to make it no longer mutable
let root_project = root_project;
let mut tree = RojoTree::new(InstanceSnapshot::new()); let mut tree = RojoTree::new(InstanceSnapshot::new());
@@ -263,14 +233,6 @@ pub enum ServeSessionError {
)] )]
NoProjectFound { path: PathBuf }, NoProjectFound { path: PathBuf },
#[error("The folder for the provided project cannot be used as a project name: {}\n\
Consider setting the `name` field on this project.", .path.display())]
FolderNameInvalid { path: PathBuf },
#[error("The file name of the provided project cannot be used as a project name: {}.\n\
Consider setting the `name` field on this project.", .path.display())]
ProjectNameInvalid { path: PathBuf },
#[error(transparent)] #[error(transparent)]
Io { Io {
#[from] #[from]

View File

@@ -1,4 +1,4 @@
use std::{borrow::Cow, collections::HashMap, path::Path}; use std::{borrow::Cow, collections::HashMap, ffi::OsStr, path::Path};
use anyhow::{bail, Context}; use anyhow::{bail, Context};
use memofs::Vfs; use memofs::Vfs;
@@ -19,7 +19,18 @@ pub fn snapshot_project(
vfs: &Vfs, vfs: &Vfs,
path: &Path, path: &Path,
) -> anyhow::Result<Option<InstanceSnapshot>> { ) -> anyhow::Result<Option<InstanceSnapshot>> {
let project = Project::load_from_slice(&vfs.read(path)?, path) let fallback_name = match path.file_name().and_then(OsStr::to_str) {
Some("default.project.json") => path
.parent()
.and_then(Path::file_name)
.and_then(OsStr::to_str),
Some(name) => name.strip_suffix(".project.json"),
None => anyhow::bail!(
"project file does not have valid utf-8 name: {}",
path.display()
),
};
let project = Project::load_exact(vfs, path, fallback_name)
.with_context(|| format!("File was not a valid Rojo project: {}", path.display()))?; .with_context(|| format!("File was not a valid Rojo project: {}", path.display()))?;
// This is not how I would normally do this, but this is a temporary // This is not how I would normally do this, but this is a temporary

View File

@@ -87,7 +87,7 @@ impl TestServeSession {
let port_string = port.to_string(); let port_string = port.to_string();
let rojo_process = Command::new(ROJO_PATH) let rojo_process = Command::new(ROJO_PATH)
.args(&[ .args([
"serve", "serve",
project_path.to_str().unwrap(), project_path.to_str().unwrap(),
"--port", "--port",
@@ -145,14 +145,14 @@ impl TestServeSession {
pub fn get_api_rojo(&self) -> Result<ServerInfoResponse, reqwest::Error> { pub fn get_api_rojo(&self) -> Result<ServerInfoResponse, reqwest::Error> {
let url = format!("http://localhost:{}/api/rojo", self.port); let url = format!("http://localhost:{}/api/rojo", self.port);
let body = reqwest::blocking::get(&url)?.text()?; let body = reqwest::blocking::get(url)?.text()?;
Ok(serde_json::from_str(&body).expect("Server returned malformed response")) Ok(serde_json::from_str(&body).expect("Server returned malformed response"))
} }
pub fn get_api_read(&self, id: Ref) -> Result<ReadResponse, reqwest::Error> { pub fn get_api_read(&self, id: Ref) -> Result<ReadResponse, reqwest::Error> {
let url = format!("http://localhost:{}/api/read/{}", self.port, id); let url = format!("http://localhost:{}/api/read/{}", self.port, id);
let body = reqwest::blocking::get(&url)?.text()?; let body = reqwest::blocking::get(url)?.text()?;
Ok(serde_json::from_str(&body).expect("Server returned malformed response")) Ok(serde_json::from_str(&body).expect("Server returned malformed response"))
} }
@@ -163,7 +163,7 @@ impl TestServeSession {
) -> Result<SubscribeResponse<'static>, reqwest::Error> { ) -> Result<SubscribeResponse<'static>, reqwest::Error> {
let url = format!("http://localhost:{}/api/subscribe/{}", self.port, cursor); let url = format!("http://localhost:{}/api/subscribe/{}", self.port, cursor);
reqwest::blocking::get(&url)?.json() reqwest::blocking::get(url)?.json()
} }
} }

View File

@@ -296,16 +296,27 @@ fn no_name_top_level_project() {
run_serve_test("no_name_top_level_project", |session, mut redactions| { run_serve_test("no_name_top_level_project", |session, mut redactions| {
let info = session.get_api_rojo().unwrap(); let info = session.get_api_rojo().unwrap();
let root_id = info.root_instance_id; let root_id = info.root_instance_id;
assert_yaml_snapshot!( assert_yaml_snapshot!(
"no_name_top_level_project_info", "no_name_top_level_project_info",
redactions.redacted_yaml(info) redactions.redacted_yaml(info)
); );
let read_response = session.get_api_read(root_id).unwrap(); let read_response = session.get_api_read(root_id).unwrap();
assert_yaml_snapshot!( assert_yaml_snapshot!(
"no_name_top_level_project_all", "no_name_top_level_project_all",
read_response.intern_and_redact(&mut redactions, root_id) read_response.intern_and_redact(&mut redactions, root_id)
); );
let project_path = session.path().join("default.project.json");
let mut project_contents = fs::read_to_string(&project_path).unwrap();
project_contents.push('\n');
fs::write(&project_path, project_contents).unwrap();
// The cursor shouldn't be changing so this snapshot is fine for testing
// the response.
let read_response = session.get_api_read(root_id).unwrap();
assert_yaml_snapshot!(
"no_name_top_level_project_all-2",
read_response.intern_and_redact(&mut redactions, root_id)
);
}); });
} }