From a4b2cf242635c38c6413ebe50e86ca0e106b5900 Mon Sep 17 00:00:00 2001
From: Jason Song <i@wolfogre.com>
Date: Thu, 5 Jan 2023 16:19:08 +0800
Subject: [PATCH] feat: calculate duration

---
 models/actions/run.go                 | 11 +-----
 models/actions/run_job.go             | 12 +-----
 models/actions/task.go                | 11 +-----
 models/actions/task_step.go           | 11 +-----
 models/actions/utils.go               | 15 +++++++
 models/actions/utils_test.go          | 57 +++++++++++++++++++++++++++
 routers/web/repo/actions/view.go      |  2 +-
 templates/repo/actions/runs_list.tmpl |  2 +-
 8 files changed, 82 insertions(+), 39 deletions(-)

diff --git a/models/actions/run.go b/models/actions/run.go
index c84082e5ce..d51bba65ec 100644
--- a/models/actions/run.go
+++ b/models/actions/run.go
@@ -82,15 +82,8 @@ func (run *ActionRun) LoadAttributes(ctx context.Context) error {
 	return nil
 }
 
-func (run *ActionRun) TakeTime() time.Duration {
-	if run.Started == 0 {
-		return 0
-	}
-	started := run.Started.AsTime()
-	if run.Status.IsDone() {
-		return run.Stopped.AsTime().Sub(started)
-	}
-	return time.Since(started).Truncate(time.Second)
+func (run *ActionRun) Duration() time.Duration {
+	return calculateDuration(run.Started, run.Stopped, run.Status)
 }
 
 func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) {
diff --git a/models/actions/run_job.go b/models/actions/run_job.go
index ffb0331a69..32c43bc563 100644
--- a/models/actions/run_job.go
+++ b/models/actions/run_job.go
@@ -43,16 +43,8 @@ func init() {
 	db.RegisterModel(new(ActionRunJob))
 }
 
-func (job *ActionRunJob) TakeTime() time.Duration {
-	if job.Started == 0 {
-		return 0
-	}
-	started := job.Started.AsTime()
-	if job.Status.IsDone() {
-		return job.Stopped.AsTime().Sub(started)
-	}
-	job.Stopped.AsTime().Sub(started)
-	return time.Since(started).Truncate(time.Second)
+func (job *ActionRunJob) Duration() time.Duration {
+	return calculateDuration(job.Started, job.Stopped, job.Status)
 }
 
 func (job *ActionRunJob) LoadRun(ctx context.Context) error {
diff --git a/models/actions/task.go b/models/actions/task.go
index 67f2b78265..d23c3bbea5 100644
--- a/models/actions/task.go
+++ b/models/actions/task.go
@@ -75,15 +75,8 @@ func init() {
 	})
 }
 
-func (task *ActionTask) TakeTime() time.Duration {
-	if task.Started == 0 {
-		return 0
-	}
-	started := task.Started.AsTime()
-	if task.Status.IsDone() {
-		return task.Stopped.AsTime().Sub(started)
-	}
-	return time.Since(started).Truncate(time.Second)
+func (task *ActionTask) Duration() time.Duration {
+	return calculateDuration(task.Started, task.Stopped, task.Status)
 }
 
 func (task *ActionTask) IsStopped() bool {
diff --git a/models/actions/task_step.go b/models/actions/task_step.go
index d70fcc222e..06cd8b556d 100644
--- a/models/actions/task_step.go
+++ b/models/actions/task_step.go
@@ -27,15 +27,8 @@ type ActionTaskStep struct {
 	Updated   timeutil.TimeStamp `xorm:"updated"`
 }
 
-func (step *ActionTaskStep) TakeTime() time.Duration {
-	if step.Started == 0 {
-		return 0
-	}
-	started := step.Started.AsTime()
-	if step.Status.IsDone() {
-		return step.Stopped.AsTime().Sub(started)
-	}
-	return time.Since(started).Truncate(time.Second)
+func (step *ActionTaskStep) Duration() time.Duration {
+	return calculateDuration(step.Started, step.Stopped, step.Status)
 }
 
 func init() {
diff --git a/models/actions/utils.go b/models/actions/utils.go
index e3511845db..12657942fc 100644
--- a/models/actions/utils.go
+++ b/models/actions/utils.go
@@ -10,8 +10,10 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"time"
 
 	auth_model "code.gitea.io/gitea/models/auth"
+	"code.gitea.io/gitea/modules/timeutil"
 	"code.gitea.io/gitea/modules/util"
 )
 
@@ -67,3 +69,16 @@ func (indexes *LogIndexes) ToDB() ([]byte, error) {
 	}
 	return buf[:i], nil
 }
+
+var timeSince = time.Since
+
+func calculateDuration(started, stopped timeutil.TimeStamp, status Status) time.Duration {
+	if started == 0 {
+		return 0
+	}
+	s := started.AsTime()
+	if status.IsDone() {
+		return stopped.AsTime().Sub(s)
+	}
+	return timeSince(s).Truncate(time.Second)
+}
diff --git a/models/actions/utils_test.go b/models/actions/utils_test.go
index 6c3679e7d2..98c048d4ef 100644
--- a/models/actions/utils_test.go
+++ b/models/actions/utils_test.go
@@ -6,6 +6,9 @@ package actions
 import (
 	"math"
 	"testing"
+	"time"
+
+	"code.gitea.io/gitea/modules/timeutil"
 
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
@@ -31,3 +34,57 @@ func TestLogIndexes_ToDB(t *testing.T) {
 		})
 	}
 }
+
+func Test_calculateDuration(t *testing.T) {
+	oldTimeSince := timeSince
+	defer func() {
+		timeSince = oldTimeSince
+	}()
+
+	timeSince = func(t time.Time) time.Duration {
+		return timeutil.TimeStamp(1000).AsTime().Sub(t)
+	}
+	type args struct {
+		started timeutil.TimeStamp
+		stopped timeutil.TimeStamp
+		status  Status
+	}
+	tests := []struct {
+		name string
+		args args
+		want time.Duration
+	}{
+		{
+			name: "unknown",
+			args: args{
+				started: 0,
+				stopped: 0,
+				status:  StatusUnknown,
+			},
+			want: 0,
+		},
+		{
+			name: "running",
+			args: args{
+				started: 500,
+				stopped: 0,
+				status:  StatusRunning,
+			},
+			want: 500 * time.Second,
+		},
+		{
+			name: "done",
+			args: args{
+				started: 500,
+				stopped: 600,
+				status:  StatusSuccess,
+			},
+			want: 100 * time.Second,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equalf(t, tt.want, calculateDuration(tt.args.started, tt.args.stopped, tt.args.status), "calculateDuration(%v, %v, %v)", tt.args.started, tt.args.stopped, tt.args.status)
+		})
+	}
+}
diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go
index de705bfe2c..2993fed622 100644
--- a/routers/web/repo/actions/view.go
+++ b/routers/web/repo/actions/view.go
@@ -156,7 +156,7 @@ func ViewPost(ctx *context_module.Context) {
 		for i, v := range steps {
 			resp.StateData.CurrentJobSteps[i] = ViewJobStep{
 				Summary:  v.Name,
-				Duration: float64(v.TakeTime() / time.Second),
+				Duration: float64(v.Duration() / time.Second),
 				Status:   v.Status.String(),
 			}
 		}
diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl
index 5d97a3553e..bcd5a4c80a 100644
--- a/templates/repo/actions/runs_list.tmpl
+++ b/templates/repo/actions/runs_list.tmpl
@@ -17,7 +17,7 @@
 			</div>
 			<div class="issue-item-right">
 				<div>{{TimeSinceUnix .Updated $.locale}}</div>
-				<div>{{.TakeTime}}</div>
+				<div>{{.Duration}}</div>
 			</div>
 		</li>
 	{{end}}