diff --git a/.github/workflows/openvmm-docs-ci.yaml b/.github/workflows/openvmm-docs-ci.yaml index 1a1e9bfd17..db955d1892 100644 --- a/.github/workflows/openvmm-docs-ci.yaml +++ b/.github/workflows/openvmm-docs-ci.yaml @@ -556,14 +556,36 @@ jobs: echo "$AgentTempDirNormal/used_artifacts/x64-linux-rustdoc" | flowey v 3 'artifact_use_from_x64-linux-rustdoc' --is-raw-string update echo "$AgentTempDirNormal/used_artifacts/x64-windows-rustdoc" | flowey v 3 'artifact_use_from_x64-windows-rustdoc' --is-raw-string update shell: bash - - name: generate consolidated gh pages html + - name: check if openvmm needs to be cloned run: |- flowey e 3 flowey_core::pipeline::artifact::resolve 1 flowey e 3 flowey_core::pipeline::artifact::resolve 2 flowey e 3 flowey_core::pipeline::artifact::resolve 0 + flowey e 3 flowey_lib_common::git_checkout 0 + flowey v 3 'flowey_lib_common::git_checkout:0:flowey_lib_common/src/git_checkout.rs:469:80' --is-raw-string --condvar flowey_lib_common::git_checkout:1:flowey_lib_common/src/git_checkout.rs:470:46 write-to-env github floweyvar2 + flowey v 3 'flowey_lib_common::git_checkout:1:flowey_lib_common/src/git_checkout.rs:470:46' write-to-env github FLOWEY_CONDITION + shell: bash + - id: flowey_lib_common__git_checkout__1 + uses: actions/checkout@v4 + with: + fetch-depth: '1' + path: repo0 + persist-credentials: ${{ env.floweyvar2 }} + name: checkout repo openvmm + if: ${{ fromJSON(env.FLOWEY_CONDITION) }} + - name: report cloned repo directories + run: |- + flowey v 3 'flowey_lib_common::git_checkout:4:flowey_core/src/node/github_context.rs:55:41' --is-raw-string update --env-source github.workspace <> "$GITHUB_ENV" + else + echo "UPLOAD_PATH=ci/$head_branch/$run_id" >> "$GITHUB_ENV" + fi + mkdir -p results + gh run \ + -R "$repo" \ + download "$run_id" \ + -p "*-vmm-tests-logs" \ + -D results + FAIL_COUNT=$(find results -name petri.failed | wc -l) + echo "FAIL_COUNT=$FAIL_COUNT" >> $GITHUB_ENV + env: + event: ${{ github.event.workflow_run.event }} + repo: ${{ github.event.workflow_run.repository.full_name }} + run_id: ${{ github.event.workflow_run.id }} + head_branch: ${{ github.event.workflow_run.head_branch }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload to Azure Blob Storage + run: | + az storage blob upload-batch \ + --destination "$BASE_URL" \ + --destination-path "$UPLOAD_PATH" \ + --source results \ + --auth-mode login + + # Store a metadata blob in a separate portion of the hierarchy so that + # it can be cheaply queried. + az storage blob upload \ + --blob-url "$BASE_URL/runs/$UPLOAD_PATH" \ + --file /dev/null \ + --metadata petrifailed="$FAIL_COUNT" \ + --auth-mode login + env: + run_id: ${{ github.event.workflow_run.id }} + + - name: Report failing tests + if: ${{ github.event.workflow_run.event == 'pull_request' && env.FAIL_COUNT > 0 }} + run: | + gh pr comment \ + -R "$repo" \ + "$pr" \ + -F - <, +struct VarDb<'a> { + vars: BTreeMap)>, } /// Implements [`flowey_core::node::RuntimeVarDb`] backed by a JSON file. @@ -47,7 +49,7 @@ impl SingleJsonFileVarDb { Ok(Self { file }) } - fn load_db(&mut self) -> VarDb { + fn load_db(&mut self) -> VarDb<'static> { self.file.rewind().unwrap(); serde_json::from_reader(&self.file).expect("corrupt runtime variable db") } @@ -57,30 +59,26 @@ impl flowey_core::node::RuntimeVarDb for SingleJsonFileVarDb { fn try_get_var(&mut self, var_name: &str) -> Option<(Vec, bool)> { let db = self.load_db(); let (is_secret, ref val) = *db.vars.get(var_name)?; - let val = val.to_string(); if is_secret { log::debug!("[db] read var: {} = ", var_name); } else { log::debug!("[db] read var: {} = {}", var_name, val); } - Some((val.into(), is_secret)) + Some((val.get().into(), is_secret)) } fn set_var(&mut self, var_name: &str, is_secret: bool, value: Vec) { + let value: &RawValue = serde_json::from_slice(&value) + .unwrap_or_else(|err| panic!("invalid JSON for var {}: {}", var_name, err)); if is_secret { log::debug!("[db] set var: {} = ", var_name) } else { - log::debug!( - "[db] set var: {} = {}", - var_name, - String::from_utf8_lossy(&value) - ) + log::debug!("[db] set var: {} = {}", var_name, value) }; let mut db = self.load_db(); - let existing = db.vars.insert( - var_name.into(), - (is_secret, serde_json::from_slice(&value).unwrap()), - ); + let existing = db + .vars + .insert(var_name.into(), (is_secret, Cow::Borrowed(value))); assert!(existing.is_none()); // all vars are one-time-write self.file.set_len(0).unwrap(); self.file.rewind().unwrap(); diff --git a/flowey/flowey_lib_hvlite/src/_jobs/consolidate_and_publish_gh_pages.rs b/flowey/flowey_lib_hvlite/src/_jobs/consolidate_and_publish_gh_pages.rs index 72d79382a9..70bc076db5 100644 --- a/flowey/flowey_lib_hvlite/src/_jobs/consolidate_and_publish_gh_pages.rs +++ b/flowey/flowey_lib_hvlite/src/_jobs/consolidate_and_publish_gh_pages.rs @@ -32,6 +32,7 @@ impl SimpleFlowNode for Node { fn imports(ctx: &mut ImportCtx<'_>) { ctx.import::(); + ctx.import::(); } fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> { @@ -42,14 +43,18 @@ impl SimpleFlowNode for Node { output, } = request; + let repo = ctx.reqv(crate::git_checkout_openvmm_repo::req::GetRepoDir); + let consolidated_html = ctx.emit_rust_stepv("generate consolidated gh pages html", |ctx| { let rendered_guide = rendered_guide.claim(ctx); let rustdoc_windows = rustdoc_windows.claim(ctx); let rustdoc_linux = rustdoc_linux.claim(ctx); + let repo = repo.claim(ctx); |rt| { let rendered_guide = rt.read(rendered_guide); let rustdoc_windows = rt.read(rustdoc_windows); let rustdoc_linux = rt.read(rustdoc_linux); + let repo = rt.read(repo); let consolidated_html = std::env::current_dir()?.join("out").absolute()?; fs_err::create_dir(&consolidated_html)?; @@ -78,6 +83,12 @@ impl SimpleFlowNode for Node { consolidated_html.join("rustdoc/linux"), )?; + // Make petri logview available under `openvmm.dev/test-results/` + flowey_lib_common::_util::copy_dir_all( + repo.join("petri/logview"), + consolidated_html.join("test-results"), + )?; + // as we do not currently have any form of "landing page", // redirect `openvmm.dev` to `openvmm.dev/guide` fs_err::write(consolidated_html.join("index.html"), REDIRECT)?; diff --git a/petri/logview/index.html b/petri/logview/index.html new file mode 100644 index 0000000000..c6dd79352c --- /dev/null +++ b/petri/logview/index.html @@ -0,0 +1,175 @@ + + + + + + Petri test results + + + + + +

Loading

+
+
+ + + \ No newline at end of file diff --git a/petri/logview/test.html b/petri/logview/test.html new file mode 100644 index 0000000000..4b7688e1eb --- /dev/null +++ b/petri/logview/test.html @@ -0,0 +1,479 @@ + + + + + + Petri test results + + + + + + +

Loading

+

+
+
+
+ + +
+
+
+ + + \ No newline at end of file diff --git a/petri/src/vm/openvmm/start.rs b/petri/src/vm/openvmm/start.rs index d9f2a5a98f..9d6847178f 100644 --- a/petri/src/vm/openvmm/start.rs +++ b/petri/src/vm/openvmm/start.rs @@ -277,11 +277,11 @@ impl PetriVmConfigOpenVmm { let mut timer = PolledTimer::new(driver); let log_source = log_source.clone(); tasks.push(driver.spawn("petri-watchdog-screenshot", async move { - let mut count = 0; + let mut image = Vec::new(); + let mut last_image = Vec::new(); loop { timer.sleep(Duration::from_secs(2)).await; - count += 1; - tracing::info!(count, "Taking screenshot."); + tracing::info!("Taking screenshot."); // Our framebuffer uses 4 bytes per pixel, approximating an // BGRA image, however it only actually contains BGR data. @@ -293,7 +293,7 @@ impl PetriVmConfigOpenVmm { let (widthsize, heightsize) = (width as usize, height as usize); let len = widthsize * heightsize * BYTES_PER_PIXEL; - let mut image = vec![0; len]; + image.resize(len, 0); for (i, line) in (0..height).zip(image.chunks_exact_mut(widthsize * BYTES_PER_PIXEL)) { @@ -304,6 +304,11 @@ impl PetriVmConfigOpenVmm { } } + if image == last_image { + tracing::info!("No change in framebuffer, skipping screenshot."); + continue; + } + let r = log_source .create_attachment("screenshot.png") .and_then(|mut f| { @@ -321,8 +326,9 @@ impl PetriVmConfigOpenVmm { if let Err(e) = r { tracing::error!(?e, "Failed to save screenshot"); } else { - tracing::info!(count, "Screenshot saved."); + tracing::info!("Screenshot saved."); } + std::mem::swap(&mut image, &mut last_image); } })); }