diff --git a/cmake/Globals.cmake b/cmake/Globals.cmake
index 5d71f72642..e9a74a1380 100644
--- a/cmake/Globals.cmake
+++ b/cmake/Globals.cmake
@@ -633,7 +633,7 @@ function(register_repository)
set(GIT_PATH ${VENDOR_PATH}/${GIT_NAME})
endif()
- set(GIT_EFFECTIVE_OUTPUTS)
+ set(GIT_EFFECTIVE_OUTPUTS ${GIT_PATH}/.ref)
foreach(output ${GIT_OUTPUTS})
list(APPEND GIT_EFFECTIVE_OUTPUTS ${GIT_PATH}/${output})
endforeach()
@@ -751,11 +751,17 @@ function(register_cmake_command)
list(APPEND MAKE_EFFECTIVE_ARGS --fresh)
endif()
+ set(MAKE_SOURCES)
+ if(TARGET clone-${MAKE_TARGET})
+ list(APPEND MAKE_SOURCES ${MAKE_CWD}/.ref)
+ endif()
+
register_command(
COMMENT "Configuring ${MAKE_TARGET}"
TARGET configure-${MAKE_TARGET}
COMMAND ${CMAKE_COMMAND} ${MAKE_EFFECTIVE_ARGS}
CWD ${MAKE_CWD}
+ SOURCES ${MAKE_SOURCES}
OUTPUTS ${MAKE_BUILD_PATH}/CMakeCache.txt
)
@@ -807,6 +813,7 @@ function(register_cmake_command)
TARGETS configure-${MAKE_TARGET}
COMMAND ${CMAKE_COMMAND} ${MAKE_BUILD_ARGS}
CWD ${MAKE_CWD}
+ SOURCES ${MAKE_SOURCES}
ARTIFACTS ${MAKE_ARTIFACTS}
)
diff --git a/scripts/build.mjs b/scripts/build.mjs
index 6fc38545a6..38da226cec 100755
--- a/scripts/build.mjs
+++ b/scripts/build.mjs
@@ -2,8 +2,15 @@
import { spawn as nodeSpawn } from "node:child_process";
import { existsSync, readFileSync, mkdirSync, cpSync, chmodSync } from "node:fs";
-import { basename, join, resolve } from "node:path";
-import { isCI, printEnvironment, startGroup } from "./utils.mjs";
+import { basename, join, relative, resolve } from "node:path";
+import {
+ formatAnnotationToHtml,
+ isCI,
+ parseAnnotations,
+ printEnvironment,
+ reportAnnotationToBuildKite,
+ startGroup,
+} from "./utils.mjs";
// https://cmake.org/cmake/help/latest/manual/cmake.1.html#generate-a-project-buildsystem
const generateFlags = [
@@ -222,16 +229,24 @@ async function spawn(command, args, options, label) {
timestamp = Date.now();
});
+ let stdoutBuffer = "";
+
let done;
if (pipe) {
const stdout = new Promise(resolve => {
subprocess.stdout.on("end", resolve);
- subprocess.stdout.on("data", data => process.stdout.write(data));
+ subprocess.stdout.on("data", data => {
+ stdoutBuffer += data.toString();
+ process.stdout.write(data);
+ });
});
const stderr = new Promise(resolve => {
subprocess.stderr.on("end", resolve);
- subprocess.stderr.on("data", data => process.stderr.write(data));
+ subprocess.stderr.on("data", data => {
+ stdoutBuffer += data.toString();
+ process.stderr.write(data);
+ });
});
done = Promise.all([stdout, stderr]);
@@ -252,9 +267,38 @@ async function spawn(command, args, options, label) {
return;
}
- if (error) {
- console.error(error);
- } else if (signalCode) {
+ let annotated;
+ try {
+ const { annotations } = parseAnnotations(stdoutBuffer);
+ for (const annotation of annotations) {
+ const content = formatAnnotationToHtml(annotation);
+ reportAnnotationToBuildKite({
+ priority: 10,
+ label: annotation.title || annotation.filename,
+ content,
+ });
+ annotated = true;
+ }
+ } catch (error) {
+ console.error(`Failed to parse annotations:`, error);
+ }
+
+ if (!annotated) {
+ const content = formatAnnotationToHtml({
+ filename: relative(process.cwd(), import.meta.filename),
+ title: "build failed",
+ content: stdoutBuffer,
+ source: "build",
+ level: "error",
+ });
+ reportAnnotationToBuildKite({
+ priority: 10,
+ label: "build failed",
+ content,
+ });
+ }
+
+ if (signalCode) {
console.error(`Command killed: ${signalCode}`);
} else {
console.error(`Command exited: code ${exitCode}`);
diff --git a/scripts/runner.node.mjs b/scripts/runner.node.mjs
index afad1c2268..ceb2d5ca5f 100755
--- a/scripts/runner.node.mjs
+++ b/scripts/runner.node.mjs
@@ -36,6 +36,7 @@ import {
isWindows,
isX64,
printEnvironment,
+ reportAnnotationToBuildKite,
startGroup,
tmpdir,
unzip,
@@ -1333,7 +1334,9 @@ function formatTestToMarkdown(result, concise) {
if (error) {
markdown += ` - ${error}`;
}
- markdown += ` on ${platform}`;
+ if (platform) {
+ markdown += ` on ${platform}`;
+ }
if (concise) {
markdown += "\n";
@@ -1396,48 +1399,6 @@ function listArtifactsFromBuildKite(glob, step) {
return [];
}
-/**
- * @typedef {object} BuildkiteAnnotation
- * @property {string} [context]
- * @property {string} label
- * @property {string} content
- * @property {"error" | "warning" | "info"} [style]
- * @property {number} [priority]
- * @property {number} [attempt]
- */
-
-/**
- * @param {BuildkiteAnnotation} annotation
- */
-function reportAnnotationToBuildKite({ context, label, content, style = "error", priority = 3, attempt = 0 }) {
- const { error, status, signal, stderr } = spawnSync(
- "buildkite-agent",
- ["annotate", "--append", "--style", `${style}`, "--context", `${context || label}`, "--priority", `${priority}`],
- {
- input: content,
- stdio: ["pipe", "ignore", "pipe"],
- encoding: "utf-8",
- timeout: spawnTimeout,
- cwd,
- },
- );
- if (status === 0) {
- return;
- }
- if (attempt > 0) {
- const cause = error ?? signal ?? `code ${status}`;
- throw new Error(`Failed to create annotation: ${label}`, { cause });
- }
- const buildLabel = getTestLabel();
- const buildUrl = getBuildUrl();
- const platform = buildUrl ? `${buildLabel}` : buildLabel;
- let errorMessage = `
`;
- if (stderr) {
- errorMessage += `\n\n\`\`\`terminal\n${escapeCodeBlock(stderr)}\n\`\`\`\n\n${label} - annotation error on ${platform}
${filePath}`;
+ } else {
+ html += `${filePath}`;
+ }
+ html += " - ";
+ }
+
+ if (title) {
+ html += title;
+ } else if (source) {
+ if (level) {
+ html += `${source} ${level}`;
+ } else {
+ html += source;
+ }
+ } else if (level) {
+ html += level;
+ } else {
+ html += "unknown error";
+ }
+
+ const buildLabel = getBuildLabel();
+ if (buildLabel) {
+ html += " on ";
+ const buildUrl = getBuildUrl();
+ if (buildUrl) {
+ html += `${buildLabel}`;
+ } else {
+ html += buildLabel;
+ }
+ }
+
+ if (concise) {
+ html += "${preview}\n`;
+ }
+ html += "\n\n\n\n";
+ }
+
+ return html;
+}
+
/**
* @typedef {Object} AnnotationResult
* @property {Annotation[]} annotations
@@ -2399,7 +2474,7 @@ export function parseAnnotations(content, options = {}) {
let length = 0;
let match;
- while (i + length <= originalLines.length && length < maxLength) {
+ while (i + length < originalLines.length && length < maxLength) {
const originalLine = originalLines[i + length++];
const line = stripAnsi(originalLine).trim();
const patternMatch = pattern.exec(line);
@@ -2548,6 +2623,46 @@ export function parseAnnotations(content, options = {}) {
};
}
+/**
+ * @typedef {object} BuildkiteAnnotation
+ * @property {string} [context]
+ * @property {string} label
+ * @property {string} content
+ * @property {"error" | "warning" | "info"} [style]
+ * @property {number} [priority]
+ * @property {number} [attempt]
+ */
+
+/**
+ * @param {BuildkiteAnnotation} annotation
+ */
+export function reportAnnotationToBuildKite({ context, label, content, style = "error", priority = 3, attempt = 0 }) {
+ const { error, status, signal, stderr } = nodeSpawnSync(
+ "buildkite-agent",
+ ["annotate", "--append", "--style", `${style}`, "--context", `${context || label}`, "--priority", `${priority}`],
+ {
+ input: content,
+ stdio: ["pipe", "ignore", "pipe"],
+ encoding: "utf-8",
+ timeout: 5_000,
+ },
+ );
+ if (status === 0) {
+ return;
+ }
+ if (attempt > 0) {
+ const cause = error ?? signal ?? `code ${status}`;
+ throw new Error(`Failed to create annotation: ${label}`, { cause });
+ }
+ const errorContent = formatAnnotationToHtml({
+ title: "annotation error",
+ content: stderr || "",
+ source: "buildkite",
+ level: "error",
+ });
+ reportAnnotationToBuildKite({ label: `${label}-error`, content: errorContent, attempt: attempt + 1 });
+}
+
/**
* @param {object} obj
* @param {number} indent