Skip to content

Commit

Permalink
Show run elapsed time / duration
Browse files Browse the repository at this point in the history
  • Loading branch information
mikebroberts committed May 9, 2024
1 parent 7fb7e64 commit eb6d32d
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 16 deletions.
5 changes: 5 additions & 0 deletions src/app/domain/github/githubWorkflowRunEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { RawGithubWorkflowRunEvent } from '../types/rawGithub/RawGithubWorkflowR
import { getMemberIds } from './githubMembership'
import { saveRuns } from './githubWorkflowRun'
import { rangeWhereSkBeginsWith } from '@symphoniacloud/dynamodb-entity-store'
import { isoDifferenceMs } from '../../util/dateAndTime'

export async function processRawRunEvents(
appState: AppState,
Expand Down Expand Up @@ -87,3 +88,7 @@ export function friendlyStatus(event: GithubWorkflowRunEvent) {
if (status === 'in_progress') return 'in progress'
return status ?? 'in progress'
}

export function elapsedTimeMs(event: GithubWorkflowRunEvent) {
return isoDifferenceMs(event.createdAt, event.updatedAt)
}
42 changes: 42 additions & 0 deletions src/app/util/dateAndTime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,48 @@ export function dateToTimestampSeconds(date: Date) {
return Math.floor(date.valueOf() / 1000)
}

const ONE_SECOND_IN_MS = 1000
const ONE_MINUTE_IN_MS = ONE_SECOND_IN_MS * 60
const ONE_HOUR_IN_MS = ONE_MINUTE_IN_MS * 60
const ONE_DAY_IN_MS = ONE_HOUR_IN_MS * 24

export function isoDifferenceAsString(isoOne: string, isoTwo: string): string {
return durationAsStringFromMs(isoDifferenceMs(isoOne, isoTwo))
}

export function isoDifferenceMs(isoOne: string, isoTwo: string) {
return timestampDifferenceMs(Date.parse(isoOne), Date.parse(isoTwo))
}

export function timestampDifferenceMs(tsOne: number, tsTwo: number) {
return Math.abs(tsOne.valueOf() - tsTwo.valueOf())
}

export function durationAsStringFromMs(duration: number): string {
const { days, hours, minutes, seconds } = durationInParts(duration)

if (days > 1) return `${days} days`
if (days === 1) return `1 day, ${hours}:${padTwo(minutes)}:${padTwo(seconds)}`
if (hours > 0) return `${hours}:${padTwo(minutes)}:${padTwo(seconds)}`
if (minutes > 0) return `0:${padTwo(minutes)}:${padTwo(seconds)}`
if (seconds > 0) return `${seconds} second${seconds === 1 ? '' : 's'}`
return '--'
}

export function durationInParts(duration: number) {
const days = Math.floor(duration / ONE_DAY_IN_MS)
const hoursRemaining = duration - days * ONE_DAY_IN_MS
const hours = Math.floor(hoursRemaining / ONE_HOUR_IN_MS)
const minutesRemaining = hoursRemaining - hours * ONE_HOUR_IN_MS
const minutes = Math.floor(minutesRemaining / ONE_MINUTE_IN_MS)
const seconds = Math.round((minutesRemaining - minutes * ONE_MINUTE_IN_MS) / ONE_SECOND_IN_MS)

return { days, hours, minutes, seconds }
}

function padTwo(input: number) {
return input < 10 ? `0${input}` : `${input}`
}
// Do something nicer for this
export function displayDateTime(clock: Clock, sourceIso: string) {
const now = clock.now()
Expand Down
28 changes: 21 additions & 7 deletions src/app/web/domainComponents/workflowComponents.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { GithubWorkflowRunEvent } from '../../domain/types/GithubWorkflowRunEvent'
import { GithubRepositoryElement } from '../../domain/types/GithubRepositoryElement'
import { a, td, tr } from '../hiccough/hiccoughElements'
import { Clock, displayDateTime } from '../../util/dateAndTime'
import { a, td, th, thead, tr } from '../hiccough/hiccoughElements'
import { Clock, displayDateTime, durationAsStringFromMs } from '../../util/dateAndTime'
import { githubAnchor } from './genericComponents'
import { commitCell, githubRepoUrl, repoCell } from './repoElementComponents'
import { runBasicStatus, WorkflowRunStatus } from '../../domain/github/githubWorkflowRunEvent'
import { elapsedTimeMs, runBasicStatus, WorkflowRunStatus } from '../../domain/github/githubWorkflowRunEvent'
import { userCell } from './userComponents'
import { removeNullAndUndefined } from '../../util/collections'

Expand All @@ -14,13 +14,25 @@ type WorkflowRowOptions = {
showDescription?: boolean
showRepo?: boolean
showWorkflow?: boolean
showElapsed?: boolean
}

const rowConfig: Record<WorkflowRowMode, WorkflowRowOptions> = {
allRepos: { showRepo: true, showWorkflow: true },
repoStatus: { showWorkflow: true },
allRepos: { showRepo: true, showWorkflow: true, showElapsed: true },
repoStatus: { showWorkflow: true, showElapsed: true },
repoActivity: { showDescription: true, showWorkflow: true },
workflowActivity: {}
workflowActivity: { showElapsed: true }
}

const columnTitles: Record<WorkflowRowMode, string[]> = {
allRepos: ['Repo', 'Workflow', 'Status', 'When', 'Duration', 'By', 'Commit'],
repoStatus: ['Workflow', 'Status', 'When', 'Duration', 'By', 'Commit'],
repoActivity: ['Type', 'Activity', 'When', 'By', 'Commit'],
workflowActivity: ['Result', 'When', 'Elapsed time', 'By', 'Commit']
}

export function workflowHeader(mode: WorkflowRowMode) {
return thead(tr(...columnTitles[mode].map((x) => th(x))))
}

export function workflowRow(clock: Clock, event: GithubWorkflowRunEvent, mode: WorkflowRowMode) {
Expand All @@ -38,10 +50,11 @@ export function workflowRowWithOptions(
event: GithubWorkflowRunEvent,
options: WorkflowRowOptions
) {
const { showDescription, showRepo, showWorkflow } = {
const { showDescription, showRepo, showWorkflow, showElapsed } = {
showDescription: false,
showRepo: false,
showWorkflow: false,
showElapsed: false,
...options
}

Expand All @@ -54,6 +67,7 @@ export function workflowRowWithOptions(
showWorkflow ? workflowCell(event) : undefined,
showDescription ? undefined : td(statusMessage(runStatus, event)),
td(displayDateTime(clock, event.updatedAt), '&nbsp;', githubAnchor(event.htmlUrl)),
showElapsed ? td(durationAsStringFromMs(elapsedTimeMs(event))) : undefined,
userCell(event.actor),
commitCell({
...event,
Expand Down
4 changes: 2 additions & 2 deletions src/app/web/views/showLatestActivityView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { GithubWorkflowRunEvent } from '../../domain/types/GithubWorkflowRunEven
import { GithubPush } from '../../domain/types/GithubPush'
import { Clock } from '../../util/dateAndTime'
import { h3, table, tbody, th, thead, tr } from '../hiccough/hiccoughElements'
import { workflowRow } from '../domainComponents/workflowComponents'
import { workflowHeader, workflowRow } from '../domainComponents/workflowComponents'
import { pushRow } from '../domainComponents/pushComponents'

export function createShowLatestActivityResponse(
Expand All @@ -15,7 +15,7 @@ export function createShowLatestActivityResponse(
h3('GitHub Actions Status'),
table(
{ class: 'table' },
thead(tr(...['Repo', 'Workflow', 'Status', 'When', 'By', 'Commit'].map((x) => th(x)))),
workflowHeader('allRepos'),
tbody(...workflowStatus.map((e) => workflowRow(clock, e, 'allRepos')))
),
h3('Recent Branch Activity'),
Expand Down
8 changes: 4 additions & 4 deletions src/app/web/views/showRepoView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { activityIsWorkflowRunActivity, GithubActivity } from '../../domain/gith
import { GithubWorkflowRunEvent } from '../../domain/types/GithubWorkflowRunEvent'
import { githubAnchor } from '../domainComponents/genericComponents'
import { GithubRepository } from '../../domain/types/GithubRepository'
import { h3, h4, table, tbody, th, thead, tr } from '../hiccough/hiccoughElements'
import { h3, h4, table, tbody } from '../hiccough/hiccoughElements'
import { pageViewResultWithoutHtmx } from './viewResultWrappers'
import { workflowRow } from '../domainComponents/workflowComponents'
import { workflowHeader, workflowRow } from '../domainComponents/workflowComponents'
import { pushRow } from '../domainComponents/pushComponents'
import { githubRepoUrl } from '../domainComponents/repoElementComponents'

Expand All @@ -29,13 +29,13 @@ export function createShowRepoResponse(
h4('GitHub Actions Status'),
table(
{ class: 'table' },
thead(tr(...['Workflow', 'Status', 'When', 'By', 'Commit'].map((x) => th(x)))),
workflowHeader('repoStatus'),
tbody(...workflowStatus.map((event) => workflowRow(clock, event, 'repoStatus')))
),
h4('Recent Activity'),
table(
{ class: 'table' },
thead(tr(...['Type', 'Activity', 'When', 'By', 'Commit'].map((x) => th(x)))),
workflowHeader('repoActivity'),
tbody(
...activity.map((event) =>
activityIsWorkflowRunActivity(event)
Expand Down
6 changes: 3 additions & 3 deletions src/app/web/views/showWorkflowView.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Clock } from '../../util/dateAndTime'
import { pageViewResultWithoutHtmx } from './viewResultWrappers'
import { GithubWorkflowRunEvent } from '../../domain/types/GithubWorkflowRunEvent'
import { h3, p, table, tbody, th, thead, tr } from '../hiccough/hiccoughElements'
import { workflowRow } from '../domainComponents/workflowComponents'
import { h3, p, table, tbody } from '../hiccough/hiccoughElements'
import { workflowHeader, workflowRow } from '../domainComponents/workflowComponents'

export function createShowWorkflowResponse(clock: Clock, runs: GithubWorkflowRunEvent[]) {
const structure =
Expand All @@ -13,7 +13,7 @@ export function createShowWorkflowResponse(clock: Clock, runs: GithubWorkflowRun
// TOEventually - when we have in-progress runs only show them if no corresponding completed event
table(
{ class: 'table' },
thead(tr(...['Result', 'When', 'By', 'Commit'].map((x) => th(x)))),
workflowHeader('workflowActivity'),
tbody(...runs.map((run) => workflowRow(clock, run, 'workflowActivity')))
)
]
Expand Down
2 changes: 2 additions & 0 deletions test/local/functional/web/latestActivity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ test('latest-activity', async () => {
<th>Workflow</th>
<th>Status</th>
<th>When</th>
<th>Duration</th>
<th>By</th>
<th>Commit</th>
</tr>
Expand All @@ -130,6 +131,7 @@ test('latest-activity', async () => {
&nbsp;
<a href="https://github.com/cicada-test-org/org-test-repo-one/actions/runs/8177622236"><i class='bi bi-github' style='color: #6e5494'></i></a>
</td>
<td>10 seconds</td>
<td>
mikebroberts
&nbsp;
Expand Down
1 change: 1 addition & 0 deletions test/local/functional/web/viewRepo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ Repository: cicada-test-org/org-test-repo-one
<th>Workflow</th>
<th>Status</th>
<th>When</th>
<th>Duration</th>
<th>By</th>
<th>Commit</th>
</tr>
Expand Down
18 changes: 18 additions & 0 deletions test/local/unit/util/dateAndTime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
dateTimeAddMinutes,
dateTimeAddSeconds,
displayDateTime,
isoDifferenceAsString,
timestampToIso
} from '../../../../src/app/util/dateAndTime'
import { Clock } from '@symphoniacloud/dynamodb-entity-store'
Expand Down Expand Up @@ -42,3 +43,20 @@ test('timestampToIso', () => {
expect(timestampToIso('2024-03-06T21:26:18Z')).toEqual('2024-03-06T21:26:18.000Z')
expect(timestampToIso('2024-03-06T23:26:18-05:00')).toEqual('2024-03-07T04:26:18.000Z')
})

test('isoDifferenceToString', () => {
expect(isoDifferenceAsString('2023-09-01T11:00:00Z', '2023-11-01T12:00:00Z')).toEqual('61 days')
expect(isoDifferenceAsString('2023-11-01T12:00:00Z', '2023-09-01T11:00:00Z')).toEqual('61 days')
expect(isoDifferenceAsString('2023-10-30T11:00:00Z', '2023-11-01T12:30:00Z')).toEqual('2 days')
expect(isoDifferenceAsString('2023-11-01T12:30:00Z', '2023-10-30T11:00:00Z')).toEqual('2 days')
expect(isoDifferenceAsString('2023-10-31T11:00:00Z', '2023-11-01T12:30:00Z')).toEqual('1 day, 1:30:00')
expect(isoDifferenceAsString('2023-11-01T12:30:00Z', '2023-10-31T11:00:00Z')).toEqual('1 day, 1:30:00')
expect(isoDifferenceAsString('2023-11-01T11:00:00Z', '2023-11-01T12:30:00Z')).toEqual('1:30:00')
expect(isoDifferenceAsString('2023-11-01T11:00:00Z', '2023-11-01T11:30:00Z')).toEqual('0:30:00')
expect(isoDifferenceAsString('2023-11-01T11:00:00Z', '2023-11-01T11:05:30Z')).toEqual('0:05:30')
expect(isoDifferenceAsString('2023-11-01T11:00:00Z', '2023-11-01T11:00:30Z')).toEqual('30 seconds')
expect(isoDifferenceAsString('2023-11-01T11:00:00Z', '2023-11-01T11:00:01.623Z')).toEqual('2 seconds')
expect(isoDifferenceAsString('2023-11-01T11:00:00Z', '2023-11-01T11:00:01.123Z')).toEqual('1 second')
expect(isoDifferenceAsString('2023-11-01T11:00:00Z', '2023-11-01T11:00:00.823Z')).toEqual('1 second')
expect(isoDifferenceAsString('2023-11-01T11:00:00Z', '2023-11-01T11:00:00.323Z')).toEqual('--')
})
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ test('successful row, all Repos', () => {
'&nbsp;',
githubAnchor('https://github.com/cicada-test-user/personal-test-repo/actions/runs/8160866530')
),
td('16 seconds'),
td('cicada-test-user', `&nbsp;`, githubAnchor(`https://github.com/cicada-test-user`)),
td(
'Test Workflow',
Expand Down Expand Up @@ -86,6 +87,7 @@ test('unsuccessful run, all Repos', () => {
'&nbsp;',
githubAnchor('https://github.com/cicada-test-user/personal-test-repo/actions/runs/8160866530')
),
td('16 seconds'),
td('cicada-test-user', `&nbsp;`, githubAnchor(`https://github.com/cicada-test-user`)),
td(
'Test Workflow',
Expand Down Expand Up @@ -161,6 +163,7 @@ test('in progress run, all repos', () => {
'&nbsp;',
githubAnchor('https://github.com/cicada-test-user/personal-test-repo/actions/runs/8160866530')
),
td('16 seconds'),
td('cicada-test-user', `&nbsp;`, githubAnchor(`https://github.com/cicada-test-user`)),
td(
'Test Workflow',
Expand Down Expand Up @@ -193,6 +196,7 @@ test('queued run, workflow activity', () => {
'&nbsp;',
githubAnchor('https://github.com/cicada-test-user/personal-test-repo/actions/runs/8160866530')
),
td('16 seconds'),
td('cicada-test-user', `&nbsp;`, githubAnchor(`https://github.com/cicada-test-user`)),
td(
'Test Workflow',
Expand Down Expand Up @@ -225,6 +229,7 @@ test('in progress run, workflow activity', () => {
'&nbsp;',
githubAnchor('https://github.com/cicada-test-user/personal-test-repo/actions/runs/8160866530')
),
td('16 seconds'),
td('cicada-test-user', `&nbsp;`, githubAnchor(`https://github.com/cicada-test-user`)),
td(
'Test Workflow',
Expand Down

0 comments on commit eb6d32d

Please sign in to comment.