diff --git a/routers/api/actions/runner/runner.go b/routers/api/actions/runner/runner.go
index 839f776fe8..a1086227eb 100644
--- a/routers/api/actions/runner/runner.go
+++ b/routers/api/actions/runner/runner.go
@@ -149,10 +149,7 @@ func (s *Service) UpdateTask(
 		return nil, status.Errorf(codes.Internal, "load job: %v", err)
 	}
 
-	if err := actions_service.CreateCommitStatus(ctx, task.Job); err != nil {
-		log.Error("Update commit status for job %v failed: %v", task.Job.ID, err)
-		// go on
-	}
+	actions_service.CreateCommitStatus(ctx, task.Job)
 
 	if req.Msg.State.Result != runnerv1.Result_RESULT_UNSPECIFIED {
 		if err := actions_service.EmitJobsIfReady(task.Job.RunID); err != nil {
diff --git a/routers/api/actions/runner/utils.go b/routers/api/actions/runner/utils.go
index 82f0da2449..cbfcd79a9d 100644
--- a/routers/api/actions/runner/utils.go
+++ b/routers/api/actions/runner/utils.go
@@ -14,6 +14,7 @@ import (
 	"code.gitea.io/gitea/modules/log"
 	secret_module "code.gitea.io/gitea/modules/secret"
 	"code.gitea.io/gitea/modules/setting"
+	"code.gitea.io/gitea/services/actions"
 
 	runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
 	"google.golang.org/protobuf/types/known/structpb"
@@ -28,6 +29,8 @@ func pickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv
 		return nil, false, nil
 	}
 
+	actions.CreateCommitStatus(ctx, t.Job)
+
 	task := &runnerv1.Task{
 		Id:              t.ID,
 		WorkflowPayload: t.Job.WorkflowPayload,
diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go
index 86894ce55b..8a208a1113 100644
--- a/routers/web/repo/actions/view.go
+++ b/routers/web/repo/actions/view.go
@@ -15,7 +15,6 @@ import (
 	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/actions"
 	context_module "code.gitea.io/gitea/modules/context"
-	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/timeutil"
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
@@ -215,10 +214,7 @@ func Rerun(ctx *context_module.Context) {
 		return
 	}
 
-	if err := actions_service.CreateCommitStatus(ctx, job); err != nil {
-		log.Error("Update commit status for job %v failed: %v", job.ID, err)
-		// go on
-	}
+	actions_service.CreateCommitStatus(ctx, job)
 
 	ctx.JSON(http.StatusOK, struct{}{})
 }
@@ -259,12 +255,7 @@ func Cancel(ctx *context_module.Context) {
 		return
 	}
 
-	for _, job := range jobs {
-		if err := actions_service.CreateCommitStatus(ctx, job); err != nil {
-			log.Error("Update commit status for job %v failed: %v", job.ID, err)
-			// go on
-		}
-	}
+	actions_service.CreateCommitStatus(ctx, jobs...)
 
 	ctx.JSON(http.StatusOK, struct{}{})
 }
diff --git a/services/actions/clear_tasks.go b/services/actions/clear_tasks.go
index 6f8e95218d..0616a5fc0d 100644
--- a/services/actions/clear_tasks.go
+++ b/services/actions/clear_tasks.go
@@ -64,12 +64,7 @@ func stopTasks(ctx context.Context, opts actions_model.FindTaskOptions) error {
 		}
 	}
 
-	for _, job := range jobs {
-		if err := CreateCommitStatus(ctx, job); err != nil {
-			log.Error("Update commit status for job %v failed: %v", job.ID, err)
-			// go on
-		}
-	}
+	CreateCommitStatus(ctx, jobs...)
 
 	return nil
 }
@@ -96,10 +91,7 @@ func CancelAbandonedJobs(ctx context.Context) error {
 			log.Warn("cancel abandoned job %v: %v", job.ID, err)
 			// go on
 		}
-		if err := CreateCommitStatus(ctx, job); err != nil {
-			log.Error("Update commit status for job %v failed: %v", job.ID, err)
-			// go on
-		}
+		CreateCommitStatus(ctx, job)
 	}
 
 	return nil
diff --git a/services/actions/commit_status.go b/services/actions/commit_status.go
index 7d674f7906..a7304bc775 100644
--- a/services/actions/commit_status.go
+++ b/services/actions/commit_status.go
@@ -6,79 +6,80 @@ package actions
 import (
 	"context"
 	"fmt"
+	"path"
 
 	actions_model "code.gitea.io/gitea/models/actions"
 	"code.gitea.io/gitea/models/db"
 	git_model "code.gitea.io/gitea/models/git"
 	user_model "code.gitea.io/gitea/models/user"
+	"code.gitea.io/gitea/modules/log"
 	api "code.gitea.io/gitea/modules/structs"
 	webhook_module "code.gitea.io/gitea/modules/webhook"
+
+	"github.com/nektos/act/pkg/jobparser"
 )
 
-func CreateCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) error {
+// CreateCommitStatus creates a commit status for the given job.
+// It won't return an error failed, but will log it, because it's not critical.
+func CreateCommitStatus(ctx context.Context, jobs ...*actions_model.ActionRunJob) {
+	for _, job := range jobs {
+		if err := createCommitStatus(ctx, job); err != nil {
+			log.Error("Failed to create commit status for job %d: %v", job.ID, err)
+		}
+	}
+}
+
+func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) error {
 	if err := job.LoadAttributes(ctx); err != nil {
 		return fmt.Errorf("load run: %w", err)
 	}
 
 	run := job.Run
-	var (
-		sha       string
-		creatorID int64
-	)
 
+	var (
+		sha   string
+		event string
+	)
 	switch run.Event {
 	case webhook_module.HookEventPush:
+		event = "push"
 		payload, err := run.GetPushEventPayload()
 		if err != nil {
 			return fmt.Errorf("GetPushEventPayload: %w", err)
 		}
-
-		// Since the payload comes from json data, we should check if it's broken, or it will cause panic
-		switch {
-		case payload.Repo == nil:
-			return fmt.Errorf("repo is missing in event payload")
-		case payload.Pusher == nil:
-			return fmt.Errorf("pusher is missing in event payload")
-		case payload.HeadCommit == nil:
+		if payload.HeadCommit == nil {
 			return fmt.Errorf("head commit is missing in event payload")
 		}
-
 		sha = payload.HeadCommit.ID
-		creatorID = payload.Pusher.ID
 	case webhook_module.HookEventPullRequest, webhook_module.HookEventPullRequestSync:
+		event = "pull_request"
 		payload, err := run.GetPullRequestEventPayload()
 		if err != nil {
 			return fmt.Errorf("GetPullRequestEventPayload: %w", err)
 		}
-
-		switch {
-		case payload.PullRequest == nil:
+		if payload.PullRequest == nil {
 			return fmt.Errorf("pull request is missing in event payload")
-		case payload.PullRequest.Head == nil:
+		} else if payload.PullRequest.Head == nil {
 			return fmt.Errorf("head of pull request is missing in event payload")
-		case payload.PullRequest.Head.Repository == nil:
-			return fmt.Errorf("head repository of pull request is missing in event payload")
-		case payload.PullRequest.Head.Repository.Owner == nil:
-			return fmt.Errorf("owner of head repository of pull request is missing in evnt payload")
 		}
-
 		sha = payload.PullRequest.Head.Sha
-		creatorID = payload.PullRequest.Head.Repository.Owner.ID
 	default:
 		return nil
 	}
 
 	repo := run.Repo
-	ctxname := job.Name
-	state := toCommitStatus(job.Status)
-	creator, err := user_model.GetUserByID(ctx, creatorID)
-	if err != nil {
-		return fmt.Errorf("GetUserByID: %w", err)
+	// TODO: store workflow name as a field in ActionRun to avoid parsing
+	runName := path.Base(run.WorkflowID)
+	if wfs, err := jobparser.Parse(job.WorkflowPayload); err == nil && len(wfs) > 0 {
+		runName = wfs[0].Name
 	}
+	ctxname := fmt.Sprintf("%s / %s (%s)", runName, job.Name, event)
+	state := toCommitStatus(job.Status)
 	if statuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptions{}); err == nil {
 		for _, v := range statuses {
 			if v.Context == ctxname {
 				if v.State == state {
+					// no need to update
 					return nil
 				}
 				break
@@ -93,6 +94,26 @@ func CreateCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
 		return fmt.Errorf("getIndexOfJob: %w", err)
 	}
 
+	description := ""
+	switch job.Status {
+	// TODO: if we want support description in different languages, we need to support i18n placeholders in it
+	case actions_model.StatusSuccess:
+		description = fmt.Sprintf("Successful in %s", job.Duration())
+	case actions_model.StatusFailure:
+		description = fmt.Sprintf("Failing after %s", job.Duration())
+	case actions_model.StatusCancelled:
+		description = "Has been cancelled"
+	case actions_model.StatusSkipped:
+		description = "Has been skipped"
+	case actions_model.StatusRunning:
+		description = "Has started running"
+	case actions_model.StatusWaiting:
+		description = "Waiting to run"
+	case actions_model.StatusBlocked:
+		description = "Blocked by required conditions"
+	}
+
+	creator := user_model.NewActionsUser()
 	if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{
 		Repo:    repo,
 		SHA:     sha,
@@ -100,9 +121,9 @@ func CreateCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
 		CommitStatus: &git_model.CommitStatus{
 			SHA:         sha,
 			TargetURL:   fmt.Sprintf("%s/jobs/%d", run.Link(), index),
-			Description: "",
+			Description: description,
 			Context:     ctxname,
-			CreatorID:   creatorID,
+			CreatorID:   creator.ID,
 			State:       state,
 		},
 	}); err != nil {
@@ -114,9 +135,9 @@ func CreateCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
 
 func toCommitStatus(status actions_model.Status) api.CommitStatusState {
 	switch status {
-	case actions_model.StatusSuccess:
+	case actions_model.StatusSuccess, actions_model.StatusSkipped:
 		return api.CommitStatusSuccess
-	case actions_model.StatusFailure, actions_model.StatusCancelled, actions_model.StatusSkipped:
+	case actions_model.StatusFailure, actions_model.StatusCancelled:
 		return api.CommitStatusFailure
 	case actions_model.StatusWaiting, actions_model.StatusBlocked:
 		return api.CommitStatusPending
diff --git a/services/actions/job_emitter.go b/services/actions/job_emitter.go
index cb2cc8d1ac..c6b6fc551e 100644
--- a/services/actions/job_emitter.go
+++ b/services/actions/job_emitter.go
@@ -45,11 +45,11 @@ func jobEmitterQueueHandle(data ...queue.Data) []queue.Data {
 }
 
 func checkJobsOfRun(ctx context.Context, runID int64) error {
-	return db.WithTx(ctx, func(ctx context.Context) error {
-		jobs, _, err := actions_model.FindRunJobs(ctx, actions_model.FindRunJobOptions{RunID: runID})
-		if err != nil {
-			return err
-		}
+	jobs, _, err := actions_model.FindRunJobs(ctx, actions_model.FindRunJobOptions{RunID: runID})
+	if err != nil {
+		return err
+	}
+	if err := db.WithTx(ctx, func(ctx context.Context) error {
 		idToJobs := make(map[string][]*actions_model.ActionRunJob, len(jobs))
 		for _, job := range jobs {
 			idToJobs[job.JobID] = append(idToJobs[job.JobID], job)
@@ -67,7 +67,11 @@ func checkJobsOfRun(ctx context.Context, runID int64) error {
 			}
 		}
 		return nil
-	})
+	}); err != nil {
+		return err
+	}
+	CreateCommitStatus(ctx, jobs...)
+	return nil
 }
 
 type jobStatusResolver struct {
diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go
index 32af1d26f6..06c461e8b5 100644
--- a/services/actions/notifier_helper.go
+++ b/services/actions/notifier_helper.go
@@ -193,12 +193,7 @@ func notify(ctx context.Context, input *notifyInput) error {
 		if jobs, _, err := actions_model.FindRunJobs(ctx, actions_model.FindRunJobOptions{RunID: run.ID}); err != nil {
 			log.Error("FindRunJobs: %v", err)
 		} else {
-			for _, job := range jobs {
-				if err := CreateCommitStatus(ctx, job); err != nil {
-					log.Error("Update commit status for job %v failed: %v", job.ID, err)
-					// go on
-				}
-			}
+			CreateCommitStatus(ctx, jobs...)
 		}
 
 	}