-
Notifications
You must be signed in to change notification settings - Fork 113
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
Run tests in CI with runner
#1190
Conversation
dfa524c
to
5b479b8
Compare
Still in progress, but I'd like to hear if there are any objections about this. I think the current version is about feature parity with the bash scripts. Note that the goal is not to replace all the bash scripts, only the ones that currently rely on logic that is spread out over several scripts, have custom flags, and are not easily discoverable / maintainable. We can (and should) keep bash scripts for simple sequences of commands. |
If the Rust I've not yet looked at the
(The features marked in bold are the ones that I use ~daily as part of my development workflow.) |
Thanks so much for writing down the list, I will let you know when they are all implemented, there are still a few missing (will keep the following checklist updated in the meanwhile):
|
c83ecfd
to
fd9af90
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think docs/development.md
and docs/INSTALL-OSX.md
should be updated as part of this change list, since some of the scripts referenced in those docs are removed.
], | ||
} | ||
} | ||
|
||
fn run_ci() -> Step { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is great that this command runs all the steps even if something fails in between.
I suggest logging a summary of the failures or the list of failed steps in the end, so that one does not have to go through the entire log to locate the problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great idea! Created #1234 to track.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that sweet issue number too
02cb03e
to
2f9c55f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did another check, it seems everything is there (for real this time?)
I added the docker save
step, which I previously missed, and also a few missing license headers to proto files that have been added in the meanwhile (I guess the previous scripts didn't really check for that).
I have attempted to make the binary compatible with mac, but I don't have a way of testing it, so please let me know if it works @daviddrysdale .
Thanks everyone for all your comments and your patience with this, I learned a lot in the process, I hope it was helpful for others too!
// Python variables. | ||
if let Ok(v) = std::env::var("PYTHONPATH") { | ||
cmd.env("PYTHONPATH", v); | ||
} | ||
|
||
// Rust compilation variables. | ||
if let Ok(v) = std::env::var("RUSTUP_HOME") { | ||
cmd.env("RUSTUP_HOME", v); | ||
} | ||
if let Ok(v) = std::env::var("CARGO_HOME") { | ||
cmd.env("CARGO_HOME", v); | ||
} | ||
|
||
// Rust runtime variables. | ||
cmd.env( | ||
"RUST_LOG", | ||
std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string()), | ||
); | ||
cmd.env("RUST_BACKTRACE", "1"); | ||
|
||
// Emscripten variables. | ||
if let Ok(v) = std::env::var("EMSDK") { | ||
cmd.env("EMSDK", v); | ||
} | ||
if let Ok(v) = std::env::var("EM_CACHE") { | ||
cmd.env("EM_CACHE", v); | ||
} | ||
if let Ok(v) = std::env::var("EM_CONFIG") { | ||
cmd.env("EM_CONFIG", v); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is propagating only some env variables to the child process, yes. I hope to clean it up later on, so that we only pass the relevant ones for each process.
runner/src/main.rs
Outdated
run_cargo_clippy(), | ||
run_cargo_test(), | ||
run_cargo_doc(), | ||
run_cargo_test_tsan(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, I also usually skip it locally. Made it a separate command, and included it in run-ci
. Thanks!
runner/src/main.rs
Outdated
build_server(&BuildServer { | ||
server_variant: "base".to_string(), | ||
server_rust_toolchain: None, | ||
server_rust_target: DEFAULT_SERVER_RUST_TARGET.to_string(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is fixed now, please let me know if it does not work for you.
/// Return whether the provided path refers to a source file that can be formatted by clang-tidy. | ||
fn is_clang_format_file(path: &PathBuf) -> bool { | ||
let filename = path.file_name().and_then(|s| s.to_str()).unwrap_or(""); | ||
filename.ends_with(".cc") || filename.ends_with(".h") || filename.ends_with(".proto") | ||
} | ||
|
||
/// Return whether the provided path refers to a Bazel file (`BUILD`, `WORKSPACE`, or `*.bzl`) | ||
fn is_bazel_file(path: &PathBuf) -> bool { | ||
let filename = path.file_name().and_then(|s| s.to_str()).unwrap_or(""); | ||
filename == "BUILD" || filename == "WORKSPACE" || filename.ends_with(".bzl") | ||
} | ||
|
||
fn is_build_file(path: &PathBuf) -> bool { | ||
let filename = path.file_name().and_then(|s| s.to_str()).unwrap_or(""); | ||
filename == "BUILD" | ||
} | ||
|
||
/// Return whether the provided path refers to a markdown file (`*.md`) | ||
fn is_markdown_file(path: &PathBuf) -> bool { | ||
let filename = path.file_name().and_then(|s| s.to_str()).unwrap_or(""); | ||
filename.ends_with(".md") | ||
} | ||
|
||
fn is_dockerfile(path: &PathBuf) -> bool { | ||
let filename = path.file_name().and_then(|s| s.to_str()).unwrap_or(""); | ||
filename.ends_with("Dockerfile") | ||
} | ||
|
||
fn is_toml_file(path: &PathBuf) -> bool { | ||
let filename = path.file_name().and_then(|s| s.to_str()).unwrap_or(""); | ||
filename.ends_with(".toml") | ||
} | ||
|
||
fn is_yaml_file(path: &PathBuf) -> bool { | ||
let filename = path.file_name().and_then(|s| s.to_str()).unwrap_or(""); | ||
filename.ends_with(".yaml") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I definitely thought about higher order functions / combinators too :) but I didn't want to do all the fun stuff myself (hint hint)
let file_content = std::fs::read_to_string(&self.path).expect("could not read file"); | ||
let todo_words = file_content | ||
.split_whitespace() | ||
.filter(|word| word.contains(&format!("{}{}", "TO", "DO"))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
.split_whitespace() | ||
.filter(|word| word.contains(&format!("{}{}", "TO", "DO"))) | ||
.filter(|word| { | ||
!(word.starts_with(&format!("{}{}(", "TO", "DO")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a TODO, fittingly :)
ps -p ${SERVER_PID} > /dev/null | ||
readonly SERVER_GONE=$? | ||
if ${SERVER_GONE} ; then | ||
echo "Runtime server has terminated early" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a TODO, I'd like to find a nicer way for this, and I think the situation is somewhat mitigated in runner by the fact that if the background process exits with a nonzero status, it will already count as failure.
fi | ||
fi | ||
|
||
kill_bg_pids |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a crude way for now, can be improved upon.
[application] | ||
manifest = "examples/abitest/config/config.toml" | ||
out = "examples/abitest/bin/config.bin" | ||
|
||
[modules] | ||
module_0 = { Cargo = { cargo_manifest = "examples/abitest/module_0/rust/Cargo.toml" } } | ||
module_1 = { Cargo = { cargo_manifest = "examples/abitest/module_1/rust/Cargo.toml" } } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pre-existing nit below: [clients] cpp
is not accurate, it would be nice to sync this with #1170.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is accurate, i.e. it is the cpp
client, and it is built via bazel
, which is what the details of the entry says.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, my bad, this isn't a fixed schema – this comment belongs elsewhere…
[application] | ||
manifest = "examples/abitest/config/config.toml" | ||
out = "examples/abitest/bin/config.bin" | ||
|
||
[modules] | ||
module_0 = { Cargo = { cargo_manifest = "examples/abitest/module_0/rust/Cargo.toml" } } | ||
module_1 = { Cargo = { cargo_manifest = "examples/abitest/module_1/rust/Cargo.toml" } } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, my bad, this isn't a fixed schema – this comment belongs elsewhere…
examples/translator/example.toml
Outdated
module = { Cargo = { cargo_manifest = "examples/translator/module/rust/Cargo.toml" } } | ||
|
||
[clients] | ||
cpp = { Bazel = { bazel_target = "//examples/translator/client:client" } } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
…specifically here. There is no C++ in this example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh good catch! I totally missed this, renamed it now.
cc @wildarch FYI (feel free to look around / add comments if you wish) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. It was a nice learning experience to review this PR :-)
runner/src/main.rs
Outdated
run_cargo_clippy(), | ||
run_cargo_test(), | ||
run_cargo_doc(), | ||
run_cargo_test_tsan(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
run_cargo_test_tsan(), |
Since the runner will be heavily dependent on |
``` | ||
|
||
The Oak Runner will launch an [Oak Runtime](concepts.md#oak-runtime), and this | ||
The Oak Loader will launch an [Oak Runtime](concepts.md#oak-runtime), and this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Glad we changed the naming, makes things clearer :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm, nice 2 review
[modules] | ||
module = { Cargo = { cargo_manifest = "examples/hello_world/module/rust/Cargo.toml" } } | ||
translator = { Cargo = { cargo_manifest = "examples/translator/module/rust/Cargo.toml" } } | ||
# This module is only built but not actually run. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How comes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because we can only run one application per example, currently. I think if we want to support alternative applications, we may as well turn them into separate examples, as @daviddrysdale suggested.
// limitations under the License. | ||
// | ||
|
||
use super::*; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it just imports everything from the parent mod; see https://doc.rust-lang.org/stable/rust-by-example/mod/super.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this specific case, which is the parent mod?
Asking since here it's at the top of the file, whereas the rust doc mentions using it in a nested scope. Is it where this is called from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mod is not a top level one. The top-level one is the one in main.rs
or lib.rs
, then each file creates its own scope based on the file name. So the fully qualified name of a type T in this file is really ::check_build_licenses::T
. super::
gets back to the parent scope, which is the on in main.rs
in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, thanks for explaining :)
I thought about that at some point, but I can see no real benefits to it, and it seems to just confuse things more for people who are not familiar with it. |
Reproducibility Index:
Reproducibility Index diff: diff --git a/reproducibility_index b/reproducibility_index
index e81a0b4..94d0bd1 100644
--- a/reproducibility_index
+++ b/reproducibility_index
@@ -3,8 +3,7 @@
5b9dc0b57f1bddb468ded79043984ad42cfa75794b9663c5ce7bf0322c9648ec ./examples/target/wasm32-unknown-unknown/release/aggregator.wasm
0dc9e4ee50ce2224e39e354a0cbe0dc337d728b9754fd8ef7ab480c48cc4efbe ./examples/target/wasm32-unknown-unknown/release/chat.wasm
f48fc1118d367ebb47d2765587622670d1b9a52e9858043173340e228a3a8664 ./examples/target/wasm32-unknown-unknown/release/database_proxy.wasm
-a0c0e2f762165c0928523fdf3a5b60a83604ac3d09f80b5ed84211428f6e5332 ./examples/target/wasm32-unknown-unknown/release/hello_world.wasm
-df1a5f037bce9ca20b556f50c7cd1bf1780cbf0d378609462f18f5d5b8589ffb ./examples/target/wasm32-unknown-unknown/release/injection.wasm
+443b6c87e761073eafe39913b43cab3103bf790ded8a29ae5f700b4afdd46443 ./examples/target/wasm32-unknown-unknown/release/hello_world.wasm
411ffccff5538a6541991e6665fb660c90c53348aa2e185b85131c02383ecd99 ./examples/target/wasm32-unknown-unknown/release/machine_learning.wasm
57ea2f959de4f1bbb70cf5acc26969726f78bb90866cc087fa77ec01c29ceb28 ./examples/target/wasm32-unknown-unknown/release/private_set_intersection.wasm
6b450333f5d36c454a186af9add9f29f9326162cb4b5516b41ff9f29cd9b87e0 ./examples/target/wasm32-unknown-unknown/release/running_average.wasm
|
Summary of main advantages compared to bash scripts:
--help
)run-ci
command); this gives reasonable confidence that nothing has been missed, which usually otherwise requires waiting to see the outputs of the CI steps, fix the (often trivial) issue locally, and wait for another cycleIncluded changes:
asan
tests