Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
167 commits
Select commit Hold shift + click to select a range
2f5cdb9
add run_attempt
Zettat123 Apr 6, 2026
d83ec3a
fix check concurrency bug
Zettat123 Apr 6, 2026
cc7ca30
fix find needs
Zettat123 Apr 6, 2026
19c82f9
fix parse 'attempt'
Zettat123 Apr 6, 2026
8b79334
remove unused field
Zettat123 Apr 6, 2026
e38cb32
remove GetLatestAttemptByRunID
Zettat123 Apr 6, 2026
5f188ca
fix tabs
Zettat123 Apr 6, 2026
eb294a3
fix
Zettat123 Apr 6, 2026
4fe29a1
fix models
Zettat123 Apr 6, 2026
738728d
fix model bugs
Zettat123 Apr 6, 2026
6918e8c
fix api
Zettat123 Apr 6, 2026
7d572e5
fix api
Zettat123 Apr 7, 2026
4c8b561
fix test
Zettat123 Apr 7, 2026
5d4a2c9
fix concurrency/rerun test
Zettat123 Apr 7, 2026
0f50150
Merge branch 'main' into run-attempt
Zettat123 Apr 7, 2026
20608e3
fix calculateDuration
Zettat123 Apr 7, 2026
6883819
fix rerun test
Zettat123 Apr 7, 2026
735c41b
improve rerun/actions log test
Zettat123 Apr 7, 2026
52c4e28
API support
Zettat123 Apr 7, 2026
870b17f
update swagger
Zettat123 Apr 7, 2026
674348a
fix test
Zettat123 Apr 7, 2026
f8c9a0e
fix lint
Zettat123 Apr 7, 2026
35bba9a
fix rerun
Zettat123 Apr 7, 2026
a7f8076
fix lint
Zettat123 Apr 7, 2026
51dfc2c
test run attempt for artifact v3
Zettat123 Apr 7, 2026
bb65c5c
Update web_src/js/components/RepoActionView.vue
Zettat123 Apr 7, 2026
7c8e2a8
improve ui
Zettat123 Apr 7, 2026
8c5c5b9
refactor actions notify
Zettat123 Apr 8, 2026
865b0c3
improve ui
Zettat123 Apr 8, 2026
9dafc83
fix attempt race condition
Zettat123 Apr 8, 2026
d1d6b5c
fix migration
Zettat123 Apr 8, 2026
3d488fb
add previous_attempt_url
Zettat123 Apr 8, 2026
9b47da3
update swagger
Zettat123 Apr 8, 2026
f354e00
update devtest
Zettat123 Apr 8, 2026
fbd56b7
add testActionRunAttemptArtifactV4
Zettat123 Apr 8, 2026
10ab98c
update swagger
Zettat123 Apr 8, 2026
db4a101
Merge branch 'main' into run-attempt
Zettat123 Apr 8, 2026
aa1a999
update migration
Zettat123 Apr 8, 2026
df5593b
fix migration
Zettat123 Apr 9, 2026
79c6455
Merge branch 'main' into run-attempt
Zettat123 Apr 9, 2026
cfcd5be
fix test
Zettat123 Apr 9, 2026
694a8a6
update API
Zettat123 Apr 10, 2026
3dc5517
update comment for migration
Zettat123 Apr 10, 2026
68eec66
fix artifacts
Zettat123 Apr 10, 2026
254a357
Merge branch 'main' into run-attempt
Zettat123 Apr 10, 2026
709943e
fix buildRerunPlan
Zettat123 Apr 10, 2026
9f0d1da
create attempt for legacy runs
Zettat123 Apr 12, 2026
333169a
fix rerun and tests
Zettat123 Apr 12, 2026
dcd3b23
Merge branch 'main' into run-attempt
Zettat123 Apr 12, 2026
019fb69
fix stale run status
Zettat123 Apr 12, 2026
b5939df
simplify view data
Zettat123 Apr 12, 2026
b743726
fix wrong created
Zettat123 Apr 12, 2026
83d8cc4
Merge branch 'main' into run-attempt
Zettat123 Apr 12, 2026
a81a17d
Merge branch 'main' into run-attempt
Zettat123 Apr 12, 2026
b6b5154
Merge branch 'main' into run-attempt
Zettat123 Apr 13, 2026
82d4190
add comment for rerun
Zettat123 Apr 13, 2026
c1acb66
Merge branch 'main' into run-attempt
Zettat123 Apr 13, 2026
9d81b30
Merge branch 'main' into run-attempt
Zettat123 Apr 13, 2026
c448b27
remove useless GetLatestAttemptID
Zettat123 Apr 13, 2026
edc05a4
add locale for 'by'
Zettat123 Apr 13, 2026
95fe0f9
fix actions view
Zettat123 Apr 13, 2026
6f1f219
add TODO
Zettat123 Apr 13, 2026
fce65d1
fix attempt_triggered_by
Zettat123 Apr 14, 2026
f4cedc6
Merge branch 'main' into run-attempt
Zettat123 Apr 14, 2026
e5fb8f0
fix test
Zettat123 Apr 14, 2026
d0b050e
Merge branch 'main' into run-attempt
Zettat123 Apr 15, 2026
87a8f84
fix FindArtifactsOptions
Zettat123 Apr 15, 2026
3e0d5ae
fix validateRerun
Zettat123 Apr 15, 2026
832ac0a
fix get attempt for artifact
Zettat123 Apr 15, 2026
c2b26b0
fix run_attempt=0 in API
Zettat123 Apr 15, 2026
523b76c
Revert "fix run_attempt=0 in API"
Zettat123 Apr 15, 2026
36d5753
improve resolve attempt for artifact
Zettat123 Apr 15, 2026
8ed3622
fix index issues
Zettat123 Apr 15, 2026
b0014d3
fix migration
Zettat123 Apr 15, 2026
b264da7
update comments for rerun
Zettat123 Apr 15, 2026
dc2b256
fix FindRunJobOptions.RunAttemptID
Zettat123 Apr 15, 2026
94e1e8a
Merge branch 'main' into run-attempt
Zettat123 Apr 15, 2026
c1e86c2
fix frontend
Zettat123 Apr 15, 2026
c190ec0
fix attempt dropdown
Zettat123 Apr 15, 2026
be6f15e
update swagger
Zettat123 Apr 16, 2026
e8ebeb9
Merge branch 'main' into run-attempt
Zettat123 Apr 16, 2026
c695284
remove legacy GenerateToken
Zettat123 Apr 16, 2026
552cede
Merge branch 'main' into run-attempt
Zettat123 Apr 17, 2026
1c966fa
Merge branch 'main' into run-attempt
Zettat123 Apr 17, 2026
4ccd5f1
fix generating actions context
Zettat123 Apr 17, 2026
98f68d9
update comments
Zettat123 Apr 17, 2026
52a178f
Merge branch 'main' into run-attempt
Zettat123 Apr 18, 2026
4f3a95e
add maxRerunAttempts
Zettat123 Apr 18, 2026
bd05a14
Merge branch 'main' into run-attempt
Zettat123 Apr 18, 2026
64f642f
make MaxRerunAttempts configurable
Zettat123 Apr 18, 2026
6636290
remove GH link
Zettat123 Apr 18, 2026
74ffcb1
fix test
Zettat123 Apr 18, 2026
796068a
fix devtest
Zettat123 Apr 18, 2026
26929f7
fix rerun test
Zettat123 Apr 18, 2026
88058a3
Merge branch 'main' into run-attempt
Zettat123 Apr 18, 2026
0bea47a
improve rerun plan
Zettat123 Apr 18, 2026
b89fe78
fix mock actions view
Zettat123 Apr 18, 2026
04af928
Merge branch 'main' into run-attempt
Zettat123 Apr 18, 2026
7519448
fix buttons
Zettat123 Apr 18, 2026
13fdb45
Restyle cancel button to match GitHub
silverwind Apr 18, 2026
a831c72
Merge branch 'main' into run-attempt
Zettat123 Apr 18, 2026
6a1f8b8
fix migration
Zettat123 Apr 18, 2026
1ee1fe0
fix run duration
Zettat123 Apr 19, 2026
e6e76f6
update comments
Zettat123 Apr 19, 2026
10515a6
some improvements
Zettat123 Apr 19, 2026
6bb4250
improve concurrency
Zettat123 Apr 19, 2026
3d31ea6
fix concurrency comments
Zettat123 Apr 19, 2026
4f3ea7e
simplify
Zettat123 Apr 19, 2026
023a9ea
simplify actions view.go
Zettat123 Apr 19, 2026
765e62f
Merge branch 'main' into run-attempt
Zettat123 Apr 19, 2026
7714e84
fix
Zettat123 Apr 19, 2026
93d7208
fix get attempt
Zettat123 Apr 19, 2026
22d6efe
fix get attempt jobs
Zettat123 Apr 19, 2026
3079068
fix migration
Zettat123 Apr 19, 2026
12ff2bc
fix job_emitter
Zettat123 Apr 19, 2026
2d225ea
add TestCancelLegacyRunBlockedByConcurrency
Zettat123 Apr 19, 2026
b216e7e
add TestLegacyRunsInCronTasks
Zettat123 Apr 19, 2026
4e72edd
Merge branch 'main' into run-attempt
Zettat123 Apr 19, 2026
4f7e347
add job link for mock actions
Zettat123 Apr 19, 2026
040fa0a
Merge branch 'main' into run-attempt
Zettat123 Apr 19, 2026
37ff47f
fix missing job title and status for mock actions
Zettat123 Apr 19, 2026
f36fc13
mock
wxiaoguang Apr 20, 2026
eaa347d
fix layout
wxiaoguang Apr 20, 2026
0bcdb87
clean up
wxiaoguang Apr 20, 2026
c7ee591
clean up
wxiaoguang Apr 20, 2026
7023941
Merge branch 'main' into run-attempt
Zettat123 Apr 20, 2026
d416bfd
Merge branch 'main' into run-attempt
Zettat123 Apr 20, 2026
6324ace
fix mock actions
Zettat123 Apr 20, 2026
589a58a
show username directly and remove bad locale
Zettat123 Apr 20, 2026
932c5e7
revert triggered_via
Zettat123 Apr 20, 2026
8530c4f
Merge branch 'main' into run-attempt
Zettat123 Apr 20, 2026
101a909
fix by_user
Zettat123 Apr 20, 2026
23bc920
fix
Zettat123 Apr 20, 2026
c05c206
fix spacing
Zettat123 Apr 20, 2026
b5d26b1
fix vertical align
Zettat123 Apr 20, 2026
3031b9c
Merge branch 'main' into run-attempt
Zettat123 Apr 20, 2026
e93574e
use flex-text-block
Zettat123 Apr 20, 2026
f0e8b96
fix dot
Zettat123 Apr 20, 2026
c30bd3b
Merge branch 'main' into run-attempt
Zettat123 Apr 20, 2026
2f1221d
Merge branch 'main' into run-attempt
Zettat123 Apr 21, 2026
4e8be5a
fix conflicts
Zettat123 Apr 21, 2026
74cef66
Merge branch 'main' into run-attempt
Zettat123 Apr 21, 2026
433b0ab
simplify relative-time datetime
wxiaoguang Apr 21, 2026
309ba3c
clarify "actions view url"
wxiaoguang Apr 21, 2026
ffe5594
Merge branch 'main' into run-attempt
wxiaoguang Apr 21, 2026
ed5c19f
Merge branch 'main' into run-attempt
Zettat123 Apr 21, 2026
9539d15
remove legacy runID check
Zettat123 Apr 21, 2026
f118f4e
Merge branch 'main' into run-attempt
Zettat123 Apr 21, 2026
977adc8
fix args
Zettat123 Apr 21, 2026
600e112
add comment for previous_attempt_url
Zettat123 Apr 22, 2026
3780102
update swagger
Zettat123 Apr 22, 2026
d067753
improve previous_attempt_url comment
Zettat123 Apr 22, 2026
49470c6
Merge branch 'main' into run-attempt
Zettat123 Apr 22, 2026
c361090
Merge branch 'main' into run-attempt
Zettat123 Apr 22, 2026
1e4d241
Keep <relative-time> ISO-only; convert at call site
silverwind Apr 22, 2026
3908d91
Merge branch 'main' into run-attempt
Zettat123 Apr 22, 2026
71ae70c
Merge branch 'main' into run-attempt
Zettat123 Apr 22, 2026
90f8f1a
Accept unix seconds in <relative-time> and simplify call sites
silverwind Apr 22, 2026
515b595
Tighten unix seconds regex to positive integers only
silverwind Apr 22, 2026
19b4449
Merge branch 'main' into run-attempt
Zettat123 Apr 22, 2026
03e225a
Merge branch 'main' into run-attempt
Zettat123 Apr 22, 2026
2f2401f
Merge branch 'main' into run-attempt
Zettat123 Apr 22, 2026
7ee346f
fix buildArtifactTooltipHtml
wxiaoguang Apr 22, 2026
b38480c
fix lint
wxiaoguang Apr 23, 2026
ec16fac
Merge branch 'main' into run-attempt
Zettat123 Apr 23, 2026
c498902
Merge branch 'main' into run-attempt
GiteaBot Apr 23, 2026
c366f09
Merge branch 'main' into run-attempt
GiteaBot Apr 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions custom/conf/app.example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2973,6 +2973,8 @@ LEVEL = Info
;; Comma-separated list of workflow directories, the first one to exist
;; in a repo is used to find Actions workflow files
;WORKFLOW_DIRS = .gitea/workflows,.github/workflows
;; Maximum number of attempts a single workflow run can have. Default value is 50.
;MAX_RERUN_ATTEMPTS = 50

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Expand Down
51 changes: 38 additions & 13 deletions models/actions/artifact.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"

"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"

Expand Down Expand Up @@ -61,7 +62,8 @@ const (
// ActionArtifact is a file that is stored in the artifact storage.
type ActionArtifact struct {
ID int64 `xorm:"pk autoincr"`
RunID int64 `xorm:"index unique(runid_name_path)"` // The run id of the artifact
RunID int64 `xorm:"index unique(runid_attempt_name_path)"` // The run id of the artifact
RunAttemptID int64 `xorm:"index unique(runid_attempt_name_path) NOT NULL DEFAULT 0"`
RunnerID int64
RepoID int64 `xorm:"index"`
OwnerID int64
Expand All @@ -80,9 +82,9 @@ type ActionArtifact struct {
// * "application/pdf", "text/html", etc.: real content type of the artifact
ContentEncodingOrType string `xorm:"content_encoding"`

ArtifactPath string `xorm:"index unique(runid_name_path)"` // The path to the artifact when runner uploads it
ArtifactName string `xorm:"index unique(runid_name_path)"` // The name of the artifact when runner uploads it
Status ArtifactStatus `xorm:"index"` // The status of the artifact, uploading, expired or need-delete
ArtifactPath string `xorm:"index unique(runid_attempt_name_path)"` // The path to the artifact when runner uploads it
ArtifactName string `xorm:"index unique(runid_attempt_name_path)"` // The name of the artifact when runner uploads it
Status ArtifactStatus `xorm:"index"` // The status of the artifact, uploading, expired or need-delete
CreatedUnix timeutil.TimeStamp `xorm:"created"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated index"`
ExpiredUnix timeutil.TimeStamp `xorm:"index"` // The time when the artifact will be expired
Expand All @@ -92,12 +94,13 @@ func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPa
if err := t.LoadJob(ctx); err != nil {
return nil, err
}
artifact, err := getArtifactByNameAndPath(ctx, t.Job.RunID, artifactName, artifactPath)
artifact, err := getArtifactByNameAndPath(ctx, t.Job.RunID, t.Job.RunAttemptID, artifactName, artifactPath)
if errors.Is(err, util.ErrNotExist) {
artifact := &ActionArtifact{
ArtifactName: artifactName,
ArtifactPath: artifactPath,
RunID: t.Job.RunID,
RunAttemptID: t.Job.RunAttemptID,
RunnerID: t.RunnerID,
RepoID: t.RepoID,
OwnerID: t.OwnerID,
Expand All @@ -122,9 +125,9 @@ func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPa
return artifact, nil
}

func getArtifactByNameAndPath(ctx context.Context, runID int64, name, fpath string) (*ActionArtifact, error) {
func getArtifactByNameAndPath(ctx context.Context, runID, runAttemptID int64, name, fpath string) (*ActionArtifact, error) {
var art ActionArtifact
has, err := db.GetEngine(ctx).Where("run_id = ? AND artifact_name = ? AND artifact_path = ?", runID, name, fpath).Get(&art)
has, err := db.GetEngine(ctx).Where("run_id = ? AND run_attempt_id = ? AND artifact_name = ? AND artifact_path = ?", runID, runAttemptID, name, fpath).Get(&art)
if err != nil {
return nil, err
} else if !has {
Expand All @@ -144,6 +147,7 @@ type FindArtifactsOptions struct {
db.ListOptions
RepoID int64
RunID int64
RunAttemptID optional.Option[int64] // use optional to allow filtering by zero (legacy artifacts have run_attempt_id=0)
ArtifactName string
Status int
FinalizedArtifactsV4 bool
Expand All @@ -163,6 +167,9 @@ func (opts FindArtifactsOptions) ToConds() builder.Cond {
if opts.RunID > 0 {
cond = cond.And(builder.Eq{"run_id": opts.RunID})
}
if opts.RunAttemptID.Has() {
cond = cond.And(builder.Eq{"run_attempt_id": opts.RunAttemptID.Value()})
}
if opts.ArtifactName != "" {
cond = cond.And(builder.Eq{"artifact_name": opts.ArtifactName})
}
Expand All @@ -186,11 +193,12 @@ type ActionArtifactMeta struct {
ExpiredUnix timeutil.TimeStamp
}

// ListUploadedArtifactsMeta returns all uploaded artifacts meta of a run
func ListUploadedArtifactsMeta(ctx context.Context, repoID, runID int64) ([]*ActionArtifactMeta, error) {
// ListUploadedArtifactsMetaByRunAttempt returns uploaded artifacts meta scoped to a specific run and attempt.
// Pass runAttemptID=0 to target legacy artifacts (pre-v331) belonging to the run.
func ListUploadedArtifactsMetaByRunAttempt(ctx context.Context, repoID, runID, runAttemptID int64) ([]*ActionArtifactMeta, error) {
arts := make([]*ActionArtifactMeta, 0, 10)
return arts, db.GetEngine(ctx).Table("action_artifact").
Where("repo_id=? AND run_id=? AND (status=? OR status=?)", repoID, runID, ArtifactStatusUploadConfirmed, ArtifactStatusExpired).
Where("repo_id=? AND run_id=? AND run_attempt_id=? AND (status=? OR status=?)", repoID, runID, runAttemptID, ArtifactStatusUploadConfirmed, ArtifactStatusExpired).
GroupBy("artifact_name").
Select("artifact_name, sum(file_size) as file_size, max(status) as status, max(expired_unix) as expired_unix").
Find(&arts)
Expand All @@ -217,12 +225,29 @@ func SetArtifactExpired(ctx context.Context, artifactID int64) error {
return err
}

// SetArtifactNeedDelete sets an artifact to need-delete, cron job will delete it
func SetArtifactNeedDelete(ctx context.Context, runID int64, name string) error {
_, err := db.GetEngine(ctx).Where("run_id=? AND artifact_name=? AND status = ?", runID, name, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusPendingDeletion})
// SetArtifactNeedDeleteByID sets an artifact to need-delete by ID, cron job will delete it.
func SetArtifactNeedDeleteByID(ctx context.Context, artifactID int64) error {
_, err := db.GetEngine(ctx).Where("id=? AND status = ?", artifactID, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusPendingDeletion})
return err
}

// SetArtifactNeedDeleteByRunAttempt sets an artifact to need-delete in a run attempt, cron job will delete it.
// runAttemptID may be 0 for legacy artifacts created before ActionRunAttempt existed.
func SetArtifactNeedDeleteByRunAttempt(ctx context.Context, runID, runAttemptID int64, name string) error {
_, err := db.GetEngine(ctx).Where("run_id=? AND run_attempt_id=? AND artifact_name=? AND status = ?", runID, runAttemptID, name, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusPendingDeletion})
return err
}

// GetArtifactsByRunAttemptAndName returns all artifacts with the given name in the specified run attempt.
// This supports both attempt-scoped data and legacy artifacts with run_attempt_id=0.
func GetArtifactsByRunAttemptAndName(ctx context.Context, runID, runAttemptID int64, artifactName string) ([]*ActionArtifact, error) {
arts := make([]*ActionArtifact, 0)
return arts, db.GetEngine(ctx).
Where("run_id = ? AND run_attempt_id = ? AND artifact_name = ?", runID, runAttemptID, artifactName).
OrderBy("id").
Find(&arts)
}

// SetArtifactDeleted sets an artifact to deleted
func SetArtifactDeleted(ctx context.Context, artifactID int64) error {
_, err := db.GetEngine(ctx).ID(artifactID).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusDeleted})
Expand Down
75 changes: 50 additions & 25 deletions models/actions/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
type ActionRun struct {
ID int64
Title string
RepoID int64 `xorm:"unique(repo_index) index(repo_concurrency)"`
RepoID int64 `xorm:"unique(repo_index)"`
Repo *repo_model.Repository `xorm:"-"`
OwnerID int64 `xorm:"index"`
WorkflowID string `xorm:"index"` // the name of workflow file
Expand All @@ -50,15 +50,20 @@ type ActionRun struct {
Status Status `xorm:"index"`
Version int `xorm:"version default 0"` // Status could be updated concomitantly, so an optimistic lock is needed
RawConcurrency string // raw concurrency
ConcurrencyGroup string `xorm:"index(repo_concurrency) NOT NULL DEFAULT ''"`
ConcurrencyCancel bool `xorm:"NOT NULL DEFAULT FALSE"`
// Started and Stopped is used for recording last run time, if rerun happened, they will be reset to 0

// Started and Stopped are identical to the latest attempt after ActionRunAttempt was introduced.
// When a rerun creates a new latest attempt, they are reset until the new attempt starts and stops.
Started timeutil.TimeStamp
Stopped timeutil.TimeStamp
// PreviousDuration is used for recording previous duration

// PreviousDuration is kept only for legacy runs created before ActionRunAttempt existed.
// New runs and reruns no longer update this field and use attempt-scoped durations instead.
PreviousDuration time.Duration
Created timeutil.TimeStamp `xorm:"created"`
Updated timeutil.TimeStamp `xorm:"updated"`

LatestAttemptID int64 `xorm:"index NOT NULL DEFAULT 0"`

Created timeutil.TimeStamp `xorm:"created"`
Updated timeutil.TimeStamp `xorm:"updated"`
}

func init() {
Expand Down Expand Up @@ -160,6 +165,31 @@ func (run *ActionRun) Duration() time.Duration {
return d
}

// GetLatestAttempt returns
// - the latest attempt of the run
// - (nil, false, nil) for legacy runs that have no attempt records
func (run *ActionRun) GetLatestAttempt(ctx context.Context) (*ActionRunAttempt, bool, error) {
if run.LatestAttemptID == 0 {
return nil, false, nil
}
attempt, err := GetRunAttemptByRepoAndID(ctx, run.RepoID, run.LatestAttemptID)
if err != nil {
return nil, false, err
}
return attempt, true, nil
}

func (run *ActionRun) GetEffectiveConcurrency(ctx context.Context) (string, bool, error) {
attempt, has, err := run.GetLatestAttempt(ctx)
if err != nil {
return "", false, err
}
if has {
return attempt.ConcurrencyGroup, attempt.ConcurrencyCancel, nil
}
return "", false, nil
}

func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) {
if run.Event == webhook_module.HookEventPush {
var payload api.PushPayload
Expand Down Expand Up @@ -406,14 +436,11 @@ func UpdateRun(ctx context.Context, run *ActionRun, cols ...string) error {

type ActionRunIndex db.ResourceIndex

func GetConcurrentRunsAndJobs(ctx context.Context, repoID int64, concurrencyGroup string, status []Status) ([]*ActionRun, []*ActionRunJob, error) {
runs, err := db.Find[ActionRun](ctx, &FindRunOptions{
RepoID: repoID,
ConcurrencyGroup: concurrencyGroup,
Status: status,
})
// GetConcurrentRunAttemptsAndJobs returns run attempts and jobs in the same concurrency group by statuses.
func GetConcurrentRunAttemptsAndJobs(ctx context.Context, repoID int64, concurrencyGroup string, status []Status) ([]*ActionRunAttempt, []*ActionRunJob, error) {
attempts, err := FindConcurrentRunAttempts(ctx, repoID, concurrencyGroup, status)
if err != nil {
return nil, nil, fmt.Errorf("find runs: %w", err)
return nil, nil, fmt.Errorf("find run attempts: %w", err)
}

jobs, err := db.Find[ActionRunJob](ctx, &FindRunJobOptions{
Expand All @@ -425,36 +452,34 @@ func GetConcurrentRunsAndJobs(ctx context.Context, repoID int64, concurrencyGrou
return nil, nil, fmt.Errorf("find jobs: %w", err)
}

return runs, jobs, nil
return attempts, jobs, nil
}

func CancelPreviousJobsByRunConcurrency(ctx context.Context, actionRun *ActionRun) ([]*ActionRunJob, error) {
if actionRun.ConcurrencyGroup == "" {
func CancelPreviousJobsByRunConcurrency(ctx context.Context, attempt *ActionRunAttempt) ([]*ActionRunJob, error) {
if attempt.ConcurrencyGroup == "" {
return nil, nil
}

var jobsToCancel []*ActionRunJob

statusFindOption := []Status{StatusWaiting, StatusBlocked}
if actionRun.ConcurrencyCancel {
if attempt.ConcurrencyCancel {
statusFindOption = append(statusFindOption, StatusRunning)
}
runs, jobs, err := GetConcurrentRunsAndJobs(ctx, actionRun.RepoID, actionRun.ConcurrencyGroup, statusFindOption)
attempts, jobs, err := GetConcurrentRunAttemptsAndJobs(ctx, attempt.RepoID, attempt.ConcurrencyGroup, statusFindOption)
if err != nil {
return nil, fmt.Errorf("find concurrent runs and jobs: %w", err)
}
jobsToCancel = append(jobsToCancel, jobs...)

// cancel runs in the same concurrency group
for _, run := range runs {
if run.ID == actionRun.ID {
for _, concurrentAttempt := range attempts {
if concurrentAttempt.RunID == attempt.RunID {
continue
}
jobs, err := db.Find[ActionRunJob](ctx, FindRunJobOptions{
RunID: run.ID,
})
jobs, err := GetRunJobsByRunAndAttemptID(ctx, concurrentAttempt.RunID, concurrentAttempt.ID)
if err != nil {
return nil, fmt.Errorf("find run %d jobs: %w", run.ID, err)
return nil, fmt.Errorf("find run %d attempt %d jobs: %w", concurrentAttempt.RunID, concurrentAttempt.ID, err)
}
jobsToCancel = append(jobsToCancel, jobs...)
}
Expand Down
Loading