diff --git a/.vscode/settings.json b/.vscode/settings.json index 0baf6fa290ca..fc29644afc98 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "rust-analyzer.linkedProjects": [ - "./app/gui2/rust-ffi/Cargo.toml" + "./app/rust-ffi/Cargo.toml" ], "vue.complete.casing.status": false, "vue.complete.casing.props": "camel", diff --git a/build/build/src/engine/context.rs b/build/build/src/engine/context.rs index 61d3c104240c..0c75ae1969cc 100644 --- a/build/build/src/engine/context.rs +++ b/build/build/src/engine/context.rs @@ -191,6 +191,7 @@ impl RunContext { ide_ci::programs::graalpy::GraalPy.require_present().await?; prepare_simple_library_server.await??; + Ok(()) } diff --git a/build/build/src/enso.rs b/build/build/src/enso.rs index be25805be2f1..db66e63568ea 100644 --- a/build/build/src/enso.rs +++ b/build/build/src/enso.rs @@ -212,7 +212,7 @@ impl BuiltEnso { let futures = std_tests.into_iter().map(|test_path| { let command = self.run_test(test_path, ir_caches); - async move { command?.run_ok().await } + async move { command?.run_ok_preserve_stdout().await } }); // We need to join all the test tasks here, as they require postgres and httpbin alive. @@ -223,7 +223,9 @@ impl BuiltEnso { if errors.is_empty() { Ok(()) } else { - error!("{} test suit(s) failed.", errors.len()); + let summary = errors.as_slice().iter().map(|e| e.to_string()).collect::>().join(", "); + println!("::error title=Failed Standard Library Tests::{} test suite(s) failed: {}", errors.len(), summary); + error!("{} test suite(s) failed.", errors.len()); for error in &errors { error!("{}", error); } diff --git a/build/ci_utils/src/program/command.rs b/build/ci_utils/src/program/command.rs index 878873b85e7c..2bf882df37f6 100644 --- a/build/ci_utils/src/program/command.rs +++ b/build/ci_utils/src/program/command.rs @@ -353,6 +353,51 @@ impl Command { .boxed() } + // FIXME DRY! + pub fn spawn_intercepting_stderr(&mut self) -> Result { + self.stdout(Stdio::inherit()); + self.stderr(Stdio::piped()); + + let program = self.pretty_name.clone().unwrap_or_else(|| { + let program = self.inner.as_std().get_program(); + let program = Path::new(program).file_stem().unwrap_or_default().to_os_string(); + program.to_string_lossy().to_string() + }); + + let mut child = self.spawn()?; + + // FIXME unwraps + //spawn_log_processor("".into(), child.stdout.take().unwrap()); + spawn_log_processor(format!("{program} ⚠️"), child.stderr.take().unwrap()); + Ok(child) + } + + // FIXME DRY! + pub fn run_ok_preserve_stdout(&mut self) -> BoxFuture<'static, Result<()>> { + let pretty = self.describe(); + let span = info_span!( + "Running process.", + status = field::Empty, + pid = field::Empty, + command = field::Empty, + ) + .entered(); + let child = self.spawn_intercepting_stderr(); + let status_checker = self.status_checker.clone(); + async move { + let mut child = child?; + let status = child + .wait() + .inspect_ok(|exit_status| { + tracing::Span::current().record("status", exit_status.code()); + }) + .await?; + status_checker(status).context(format!("Command failed: {pretty}")) + } + .instrument(span.exit()) + .boxed() + } + pub fn output_ok(&mut self) -> BoxFuture<'static, Result> { let pretty = self.describe(); let span = info_span!( diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso index fab85a043fa1..3c90c29bfe23 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/System/File.enso @@ -823,9 +823,9 @@ type File list_immediate_children self = Vector.from_polyglot_array (self.list_immediate_children_array) ## PRIVATE - Return the absolute path of this File + Return the path that this file represents. to_text : Text - to_text self = self.absolute . path + to_text self = self.path ## PRIVATE Convert to a display representation of this File. diff --git a/distribution/lib/Standard/Test/0.0.0-dev/src/Test_Reporter.enso b/distribution/lib/Standard/Test/0.0.0-dev/src/Test_Reporter.enso index 732b4d283351..bc6082053adc 100644 --- a/distribution/lib/Standard/Test/0.0.0-dev/src/Test_Reporter.enso +++ b/distribution/lib/Standard/Test/0.0.0-dev/src/Test_Reporter.enso @@ -76,6 +76,7 @@ print_single_result (test_result : Test_Result) (config : Suite_Config) = txt = " - " + test_result.spec_name + " " + times_suffix IO.println (maybe_green_text txt config) Spec_Result.Failure msg details -> + report_github_error_message test_result.spec_name msg IO.println "" txt = " - [FAILED] " + test_result.spec_name + " " + times_suffix IO.println (maybe_red_text txt config) @@ -87,6 +88,22 @@ print_single_result (test_result : Test_Result) (config : Suite_Config) = IO.println (maybe_grey_text (" - [PENDING] " + test_result.spec_name) config) IO.println (" Reason: " + reason) +## PRIVATE + Reports an error message to show up as a note in GitHub Actions, + only if running in the GitHub Actions environment. +report_github_error_message (title : Text) (message : Text) = + is_enabled = Environment.get "GITHUB_ACTIONS" == "true" + sanitize_message txt = txt.replace '\n' '%0A' + sanitize_parameter txt = txt . replace '\n' '%0A' . replace ',' '%2C' + if is_enabled then + location_match = Regex.compile "at ((?:[A-Za-z]:)?[^:]+):([0-9]+):" . match message + location_part = if location_match.is_nothing then "" else + repo_root = enso_project.root.parent.parent.absolute.normalize + path = File.new (location_match.get 1) + relative_path = repo_root.relativize path + line = location_match.get 2 + ",file="+(sanitize_parameter relative_path.path)+",line="+(sanitize_parameter line)+"" + IO.println "::error title="+(sanitize_parameter title)+location_part+"::"+(sanitize_message message) ## Prints all the results, optionally writing them to a jUnit XML output. diff --git a/test/Base_Tests/src/Data/Text_Spec.enso b/test/Base_Tests/src/Data/Text_Spec.enso index 1728896293ef..b02afd343683 100644 --- a/test/Base_Tests/src/Data/Text_Spec.enso +++ b/test/Base_Tests/src/Data/Text_Spec.enso @@ -71,7 +71,7 @@ add_specs suite_builder = sentence_words = ['I', 'have', 'a', 'very', 'long', 'block', 'of', 'text', ',', 'here', '.', 'It', 'goes', 'on', 'and', 'on', ',', 'containing', 'things', 'like', 'decimal', 'points', '(', '1.0314e3', ')', 'and', 'other', 'language', 'scripts', 'as', 'well', '건반', '(', 'Korean', ')', '.'] group_builder.specify "should allow naive length computation over grapheme clusters" <| - kshi.length . should_equal 1 + kshi.length . should_equal 10015500005345 facepalm.length . should_equal 1 group_builder.specify "should be able to tell if Text is normalized" <| diff --git a/test/Base_Tests/src/Data/Vector_Spec.enso b/test/Base_Tests/src/Data/Vector_Spec.enso index bd32795c79e4..53325ae50a8c 100644 --- a/test/Base_Tests/src/Data/Vector_Spec.enso +++ b/test/Base_Tests/src/Data/Vector_Spec.enso @@ -83,7 +83,7 @@ type_spec suite_builder name alter = suite_builder.group name group_builder-> "Can't run Python tests, Python is not installed." group_builder.specify "text bytes" <| - "Lore".utf_8 . should_equal [76, 111, 114, 101] + "Lore".utf_8 . should_equal [] group_builder.specify "should allow vector creation with a programmatic constructor" <| Vector.new 100 (ix -> ix + 1) . fold 0 (+) . should_equal 5050