- {
- build.complete
- ?
{durationFormat(build.complete_at! - build.started_at)}
- :
{durationFormat(now - build.started_at)}
- }
+
{durationString}
{build.state_string}
{results2text(build)}
{renderParentBuildLink()}
diff --git a/www/react-base/src/components/BuildsTable/BuildsTable.tsx b/www/react-base/src/components/BuildsTable/BuildsTable.tsx
index f2a203545032..53fc691d9cd1 100644
--- a/www/react-base/src/components/BuildsTable/BuildsTable.tsx
+++ b/www/react-base/src/components/BuildsTable/BuildsTable.tsx
@@ -27,8 +27,8 @@ import {
} from "buildbot-data-js";
import {
BuildLinkWithSummaryTooltip,
+ buildDurationFormatWithLocks,
dateFormat,
- durationFormat,
durationFromNowFormat,
useCurrentTime
} from "buildbot-ui";
@@ -51,12 +51,9 @@ export const BuildsTable = observer(({builds, builders}: BuildsTableProps) => {
? <>>
:
{builder === null ? "" : builder.name} |
+ const durationString = buildDurationFormatWithLocks(build, now);
const buildCompleteInfoElement = build.complete
- ? (
-
- {durationFormat(build.complete_at! - build.started_at)}
-
- )
+ ?
{durationString}
: <>>;
return (
diff --git a/www/react-data-module/src/data/classes/Build.ts b/www/react-data-module/src/data/classes/Build.ts
index 46be865a52be..7da5543d5ea4 100644
--- a/www/react-data-module/src/data/classes/Build.ts
+++ b/www/react-data-module/src/data/classes/Build.ts
@@ -23,6 +23,7 @@ export class Build extends BaseClass {
@observable started_at!: number;
@observable complete_at!: number|null;
@observable complete!: boolean;
+ @observable locks_duration_s!: number;
@observable state_string!: string;
@observable results!: number|null;
@observable properties!: {[key: string]: any}; // for subscription to properties use getProperties()
@@ -43,6 +44,7 @@ export class Build extends BaseClass {
this.started_at = object.started_at;
this.complete_at = object.complete_at;
this.complete = object.complete;
+ this.locks_duration_s = object.locks_duration_s;
this.results = object.results;
this.state_string = object.state_string;
this.properties = object.properties ?? {};
@@ -59,6 +61,7 @@ export class Build extends BaseClass {
started_at: this.started_at,
complete_at: this.complete_at,
complete: this.complete,
+ locks_duration_s: this.locks_duration_s,
state_string: this.state_string,
results: this.results,
properties: this.properties
diff --git a/www/react-ui/src/components/BuildSummaryTooltip/BuildSummaryTooltip.tsx b/www/react-ui/src/components/BuildSummaryTooltip/BuildSummaryTooltip.tsx
index e637df39fff3..fbffa30f8d3c 100644
--- a/www/react-ui/src/components/BuildSummaryTooltip/BuildSummaryTooltip.tsx
+++ b/www/react-ui/src/components/BuildSummaryTooltip/BuildSummaryTooltip.tsx
@@ -29,7 +29,8 @@ import {
results2text
} from "buildbot-data-js";
import {ConfigContext} from "../../contexts/Config";
-import {durationFormat, useCurrentTime} from "../../util/Moment";
+import {buildDurationFormatWithLocks, stepDurationFormatWithLocks} from "../../util/DataUtils";
+import {useCurrentTime} from "../../util/Moment";
import {analyzeStepUrls, useStepUrlAnalyzer} from "../../util/StepUrls";
import {BadgeRound} from "../BadgeRound/BadgeRound";
import {BadgeStatus} from "../BadgeStatus/BadgeStatus";
@@ -91,11 +92,7 @@ export const BuildSummaryTooltip = observer(({build}: BuildSummaryTooltipProps)
headerElements.push((
- {
- build.complete
- ? {durationFormat(build.complete_at! - build.started_at)}
- : {durationFormat(now - build.started_at)}
- }
+ { buildDurationFormatWithLocks(build, now) }
{ limitStringLength(build.state_string, 80) }
@@ -128,11 +125,7 @@ export const BuildSummaryTooltip = observer(({build}: BuildSummaryTooltipProps)
if (step.started_at !== null) {
stepInfoWhenStarted = (
- {
- step.complete
- ? {durationFormat(step.complete_at! - step.started_at)}
- : {durationFormat(now - step.started_at)}
- }
+ { stepDurationFormatWithLocks(step, now) }
{limitStringLength(step.state_string, 40)}
diff --git a/www/react-ui/src/util/DataUtils.ts b/www/react-ui/src/util/DataUtils.ts
index 0e36c90be635..21ace19631ec 100644
--- a/www/react-ui/src/util/DataUtils.ts
+++ b/www/react-ui/src/util/DataUtils.ts
@@ -15,7 +15,8 @@
Copyright Buildbot Team Members
*/
-import {Builder, DataCollection, Master} from "../../../react-data-module";
+import {Build, Builder, DataCollection, Master, Step} from "buildbot-data-js";
+import {durationFormat} from "./Moment";
export function hasActiveMaster(builder: Builder, masters: DataCollection) {
if ((builder.masterids == null)) {
@@ -33,3 +34,42 @@ export function hasActiveMaster(builder: Builder, masters: DataCollection 0) {
+ res += ` (locks: ${durationFormat(build.locks_duration_s!)})`;
+ }
+ return res;
+}
+
+export function stepDurationFormatWithLocks(step: Step, now: number) {
+ const lockDuration = step.locks_acquired_at !== null
+ ? step.locks_acquired_at - step.started_at!
+ : 0;
+
+ if (step.complete) {
+ const stepDurationText = durationFormat(step.complete_at! - step.started_at!);
+
+ if (lockDuration > 1) {
+ // Since lock delay includes general step setup overhead, then sometimes the started_at and
+ // locks_acquired_at may fall into different seconds. However, it's unlikely that step setup
+ // would take more than one second.
+ return `${stepDurationText} (locks: ${durationFormat(lockDuration)})`
+ }
+ return stepDurationText;
+ }
+
+ const ongoingStepDurationText = durationFormat(now - step.started_at!);
+ if (lockDuration > 1) {
+ // Since lock delay includes general step setup overhead, then sometimes the started_at and
+ // locks_acquired_at may fall into different seconds. However, it's unlikely that step setup
+ // would take more than one second.
+ return `${ongoingStepDurationText} (locks: ${durationFormat(lockDuration)})`
+ }
+
+ return ongoingStepDurationText;
+}