From 385994295dac0536bab720f76ec12e9140d0ea40 Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Tue, 10 Mar 2026 15:14:48 -0600 Subject: [PATCH] Replace index with id in actions routes (#36842) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR migrates the web Actions run/job routes from index-based `runIndex` or `jobIndex` to database IDs. **⚠️ BREAKING ⚠️**: Existing saved links/bookmarks that use the old index-based URLs will no longer resolve after this change. Improvements of this change: - Previously, `jobIndex` depended on list order, making it hard to locate a specific job. Using `jobID` provides stable addressing. - Web routes now align with API, which already use IDs. - Behavior is closer to GitHub, which exposes run/job IDs in URLs. - Provides a cleaner base for future features without relying on list order. - #36388 this PR improves the support for reusable workflows. If a job uses a reusable workflow, it may contain multiple child jobs, which makes relying on job index to locate a job much more complicated --------- Signed-off-by: Zettat123 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- models/actions/run.go | 6 +- models/actions/run_job.go | 20 +- models/actions/task.go | 4 +- models/git/commit_status_test.go | 2 +- .../action_run.yml | 9 + .../action_run_job.yml | 10 + .../commit_status.yml | 29 +++ .../commit_status_summary.yml | 19 ++ .../repository.yml | 9 + models/migrations/migrations.go | 1 + models/migrations/v1_26/v326.go | 216 ++++++++++++++++++ models/migrations/v1_26/v326_test.go | 104 +++++++++ routers/api/v1/repo/action.go | 8 +- routers/api/v1/repo/actions_run.go | 8 +- routers/common/actions.go | 15 +- routers/web/devtest/mock_actions.go | 4 +- routers/web/repo/actions/view.go | 167 +++++++------- services/actions/commit_status.go | 31 +-- services/actions/rerun.go | 3 + services/convert/convert.go | 14 +- templates/devtest/repo-action-view.tmpl | 4 +- templates/repo/actions/view.tmpl | 4 +- templates/repo/actions/view_component.tmpl | 4 +- tests/integration/actions_concurrency_test.go | 42 ++-- tests/integration/actions_delete_run_test.go | 31 ++- tests/integration/actions_log_test.go | 18 +- tests/integration/actions_rerun_test.go | 11 +- tests/integration/actions_route_test.go | 100 ++++++++ tests/integration/api_actions_run_test.go | 8 +- tests/integration/repo_webhook_test.go | 10 +- web_src/js/components/RepoActionView.vue | 14 +- web_src/js/components/WorkflowGraph.vue | 12 +- web_src/js/features/repo-actions.ts | 4 +- 33 files changed, 713 insertions(+), 228 deletions(-) create mode 100644 models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/action_run.yml create mode 100644 models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/action_run_job.yml create mode 100644 models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/commit_status.yml create mode 100644 models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/commit_status_summary.yml create mode 100644 models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/repository.yml create mode 100644 models/migrations/v1_26/v326.go create mode 100644 models/migrations/v1_26/v326_test.go create mode 100644 tests/integration/actions_route_test.go diff --git a/models/actions/run.go b/models/actions/run.go index 99e6267071..e293a6056f 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -70,14 +70,14 @@ func (run *ActionRun) HTMLURL() string { if run.Repo == nil { return "" } - return fmt.Sprintf("%s/actions/runs/%d", run.Repo.HTMLURL(), run.Index) + return fmt.Sprintf("%s/actions/runs/%d", run.Repo.HTMLURL(), run.ID) } func (run *ActionRun) Link() string { if run.Repo == nil { return "" } - return fmt.Sprintf("%s/actions/runs/%d", run.Repo.Link(), run.Index) + return fmt.Sprintf("%s/actions/runs/%d", run.Repo.Link(), run.ID) } func (run *ActionRun) WorkflowLink() string { @@ -299,7 +299,7 @@ func CancelJobs(ctx context.Context, jobs []*ActionRunJob) ([]*ActionRunJob, err if err := StopTask(ctx, job.TaskID, StatusCancelled); err != nil { return cancelledJobs, err } - updatedJob, err := GetRunJobByID(ctx, job.ID) + updatedJob, err := GetRunJobByRunAndID(ctx, job.RunID, job.ID) if err != nil { return cancelledJobs, fmt.Errorf("get job: %w", err) } diff --git a/models/actions/run_job.go b/models/actions/run_job.go index 430f585663..c752e61b7d 100644 --- a/models/actions/run_job.go +++ b/models/actions/run_job.go @@ -118,13 +118,25 @@ func (job *ActionRunJob) ParseJob() (*jobparser.Job, error) { return workflowJob, nil } -func GetRunJobByID(ctx context.Context, id int64) (*ActionRunJob, error) { +func GetRunJobByRepoAndID(ctx context.Context, repoID, jobID int64) (*ActionRunJob, error) { var job ActionRunJob - has, err := db.GetEngine(ctx).Where("id=?", id).Get(&job) + has, err := db.GetEngine(ctx).Where("id=? AND repo_id=?", jobID, repoID).Get(&job) if err != nil { return nil, err } else if !has { - return nil, fmt.Errorf("run job with id %d: %w", id, util.ErrNotExist) + return nil, fmt.Errorf("run job with id %d: %w", jobID, util.ErrNotExist) + } + + return &job, nil +} + +func GetRunJobByRunAndID(ctx context.Context, runID, jobID int64) (*ActionRunJob, error) { + var job ActionRunJob + has, err := db.GetEngine(ctx).Where("id=? AND run_id=?", jobID, runID).Get(&job) + if err != nil { + return nil, err + } else if !has { + return nil, fmt.Errorf("run job with id %d: %w", jobID, util.ErrNotExist) } return &job, nil @@ -168,7 +180,7 @@ func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, col if job.RunID == 0 { var err error - if job, err = GetRunJobByID(ctx, job.ID); err != nil { + if job, err = GetRunJobByRepoAndID(ctx, job.RepoID, job.ID); err != nil { return 0, err } } diff --git a/models/actions/task.go b/models/actions/task.go index c35395ceed..e092d6fbbd 100644 --- a/models/actions/task.go +++ b/models/actions/task.go @@ -114,7 +114,7 @@ func (task *ActionTask) GetRepoLink() string { func (task *ActionTask) LoadJob(ctx context.Context) error { if task.Job == nil { - job, err := GetRunJobByID(ctx, task.JobID) + job, err := GetRunJobByRepoAndID(ctx, task.RepoID, task.JobID) if err != nil { return err } @@ -388,6 +388,7 @@ func UpdateTaskByState(ctx context.Context, runnerID int64, state *runnerv1.Task } if _, err := UpdateRunJob(ctx, &ActionRunJob{ ID: task.JobID, + RepoID: task.RepoID, Status: task.Status, Stopped: task.Stopped, }, nil); err != nil { @@ -449,6 +450,7 @@ func StopTask(ctx context.Context, taskID int64, status Status) error { task.Stopped = now if _, err := UpdateRunJob(ctx, &ActionRunJob{ ID: task.JobID, + RepoID: task.RepoID, Status: task.Status, Stopped: task.Stopped, }, nil); err != nil { diff --git a/models/git/commit_status_test.go b/models/git/commit_status_test.go index d1b9dfc3bf..f565550c53 100644 --- a/models/git/commit_status_test.go +++ b/models/git/commit_status_test.go @@ -243,7 +243,7 @@ func TestCommitStatusesHideActionsURL(t *testing.T) { statuses := []*git_model.CommitStatus{ { RepoID: repo.ID, - TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), run.Index), + TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), run.ID), }, { RepoID: repo.ID, diff --git a/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/action_run.yml b/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/action_run.yml new file mode 100644 index 0000000000..342adb2a04 --- /dev/null +++ b/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/action_run.yml @@ -0,0 +1,9 @@ +# type ActionRun struct { +# ID int64 `xorm:"pk autoincr"` +# RepoID int64 `xorm:"index"` +# Index int64 +# } +- + id: 106 + repo_id: 1 + index: 7 diff --git a/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/action_run_job.yml b/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/action_run_job.yml new file mode 100644 index 0000000000..4f90a4495c --- /dev/null +++ b/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/action_run_job.yml @@ -0,0 +1,10 @@ +# type ActionRunJob struct { +# ID int64 `xorm:"pk autoincr"` +# RunID int64 `xorm:"index"` +# } +- + id: 530 + run_id: 106 +- + id: 531 + run_id: 106 diff --git a/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/commit_status.yml b/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/commit_status.yml new file mode 100644 index 0000000000..ceff4c9993 --- /dev/null +++ b/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/commit_status.yml @@ -0,0 +1,29 @@ +# type CommitStatus struct { +# ID int64 `xorm:"pk autoincr"` +# RepoID int64 `xorm:"index"` +# TargetURL string +# } +- + id: 10 + repo_id: 1 + target_url: /testuser/repo1/actions/runs/7/jobs/0 +- + id: 11 + repo_id: 1 + target_url: /testuser/repo1/actions/runs/7/jobs/1 +- + id: 12 + repo_id: 1 + target_url: /otheruser/badrepo/actions/runs/7/jobs/0 +- + id: 13 + repo_id: 1 + target_url: /testuser/repo1/actions/runs/10/jobs/0 +- + id: 14 + repo_id: 1 + target_url: /testuser/repo1/actions/runs/7/jobs/3 +- + id: 15 + repo_id: 1 + target_url: https://ci.example.com/build/123 diff --git a/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/commit_status_summary.yml b/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/commit_status_summary.yml new file mode 100644 index 0000000000..580b2a4f04 --- /dev/null +++ b/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/commit_status_summary.yml @@ -0,0 +1,19 @@ +# type CommitStatusSummary struct { +# ID int64 `xorm:"pk autoincr"` +# RepoID int64 `xorm:"index"` +# SHA string `xorm:"VARCHAR(64) NOT NULL"` +# State string `xorm:"VARCHAR(7) NOT NULL"` +# TargetURL string +# } +- + id: 20 + repo_id: 1 + sha: "012345" + state: success + target_url: /testuser/repo1/actions/runs/7/jobs/0 +- + id: 21 + repo_id: 1 + sha: "678901" + state: success + target_url: https://ci.example.com/build/123 diff --git a/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/repository.yml b/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/repository.yml new file mode 100644 index 0000000000..86cfb926e4 --- /dev/null +++ b/models/migrations/fixtures/Test_FixCommitStatusTargetURLToUseRunAndJobID/repository.yml @@ -0,0 +1,9 @@ +# type Repository struct { +# ID int64 `xorm:"pk autoincr"` +# OwnerName string +# Name string +# } +- + id: 1 + owner_name: testuser + name: repo1 diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 9975729fd6..ab14e8a8e7 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -400,6 +400,7 @@ func prepareMigrationTasks() []*migration { newMigration(323, "Add support for actions concurrency", v1_26.AddActionsConcurrency), newMigration(324, "Fix closed milestone completeness for milestones with no issues", v1_26.FixClosedMilestoneCompleteness), newMigration(325, "Fix missed repo_id when migrate attachments", v1_26.FixMissedRepoIDWhenMigrateAttachments), + newMigration(326, "Migrate commit status target URL to use run ID and job ID", v1_26.FixCommitStatusTargetURLToUseRunAndJobID), } return preparedMigrations } diff --git a/models/migrations/v1_26/v326.go b/models/migrations/v1_26/v326.go new file mode 100644 index 0000000000..1ec0af76a0 --- /dev/null +++ b/models/migrations/v1_26/v326.go @@ -0,0 +1,216 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_26 + +import ( + "fmt" + "net/url" + "strconv" + "strings" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + + "xorm.io/xorm" +) + +const actionsRunPath = "/actions/runs/" + +type migrationRepository struct { + ID int64 + OwnerName string + Name string +} + +type migrationActionRun struct { + ID int64 + RepoID int64 + Index int64 +} + +type migrationActionRunJob struct { + ID int64 + RunID int64 +} + +type migrationCommitStatus struct { + ID int64 + RepoID int64 + TargetURL string +} + +func FixCommitStatusTargetURLToUseRunAndJobID(x *xorm.Engine) error { + runByIndexCache := make(map[int64]map[int64]*migrationActionRun) + jobsByRunIDCache := make(map[int64][]int64) + repoLinkCache := make(map[int64]string) + + if err := migrateCommitStatusTargetURL(x, "commit_status", runByIndexCache, jobsByRunIDCache, repoLinkCache); err != nil { + return err + } + return migrateCommitStatusTargetURL(x, "commit_status_summary", runByIndexCache, jobsByRunIDCache, repoLinkCache) +} + +func migrateCommitStatusTargetURL( + x *xorm.Engine, + table string, + runByIndexCache map[int64]map[int64]*migrationActionRun, + jobsByRunIDCache map[int64][]int64, + repoLinkCache map[int64]string, +) error { + const batchSize = 500 + var lastID int64 + + for { + var rows []migrationCommitStatus + sess := x.Table(table). + Where("target_url LIKE ?", "%"+actionsRunPath+"%"). + And("id > ?", lastID). + Asc("id"). + Limit(batchSize) + if err := sess.Find(&rows); err != nil { + return fmt.Errorf("query %s: %w", table, err) + } + if len(rows) == 0 { + return nil + } + + for _, row := range rows { + lastID = row.ID + if row.TargetURL == "" { + continue + } + + repoLink, err := getRepoLinkCached(x, repoLinkCache, row.RepoID) + if err != nil || repoLink == "" { + if err != nil { + log.Warn("convert %s id=%d getRepoLinkCached: %v", table, row.ID, err) + } else { + log.Warn("convert %s id=%d: repo=%d not found", table, row.ID, row.RepoID) + } + continue + } + + runNum, jobNum, ok := parseTargetURL(row.TargetURL, repoLink) + if !ok { + continue + } + + run, err := getRunByIndexCached(x, runByIndexCache, row.RepoID, runNum) + if err != nil || run == nil { + if err != nil { + log.Warn("convert %s id=%d getRunByIndexCached: %v", table, row.ID, err) + } else { + log.Warn("convert %s id=%d: run not found for repo_id=%d run_index=%d", table, row.ID, row.RepoID, runNum) + } + continue + } + + jobID, ok, err := getJobIDByIndexCached(x, jobsByRunIDCache, run.ID, jobNum) + if err != nil || !ok { + if err != nil { + log.Warn("convert %s id=%d getJobIDByIndexCached: %v", table, row.ID, err) + } else { + log.Warn("convert %s id=%d: job not found for run_id=%d job_index=%d", table, row.ID, run.ID, jobNum) + } + continue + } + + oldURL := row.TargetURL + newURL := fmt.Sprintf("%s%s%d/jobs/%d", repoLink, actionsRunPath, run.ID, jobID) // expect: {repo_link}/actions/runs/{run_id}/jobs/{job_id} + if oldURL == newURL { + continue + } + + if _, err := x.Table(table).ID(row.ID).Cols("target_url").Update(&migrationCommitStatus{TargetURL: newURL}); err != nil { + return fmt.Errorf("update %s id=%d target_url from %s to %s: %w", table, row.ID, oldURL, newURL, err) + } + } + } +} + +func getRepoLinkCached(x *xorm.Engine, cache map[int64]string, repoID int64) (string, error) { + if link, ok := cache[repoID]; ok { + return link, nil + } + repo := &migrationRepository{} + has, err := x.Table("repository").Where("id=?", repoID).Get(repo) + if err != nil { + return "", err + } + if !has { + cache[repoID] = "" + return "", nil + } + link := setting.AppSubURL + "/" + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name) + cache[repoID] = link + return link, nil +} + +func getRunByIndexCached(x *xorm.Engine, cache map[int64]map[int64]*migrationActionRun, repoID, runIndex int64) (*migrationActionRun, error) { + if repoCache, ok := cache[repoID]; ok { + if run, ok := repoCache[runIndex]; ok { + if run == nil { + return nil, fmt.Errorf("run repo_id=%d run_index=%d not found", repoID, runIndex) + } + return run, nil + } + } + + var run migrationActionRun + has, err := x.Table("action_run").Where("repo_id=? AND `index`=?", repoID, runIndex).Get(&run) + if err != nil { + return nil, err + } + if !has { + if cache[repoID] == nil { + cache[repoID] = make(map[int64]*migrationActionRun) + } + cache[repoID][runIndex] = nil + return nil, fmt.Errorf("run repo_id=%d run_index=%d not found", repoID, runIndex) + } + if cache[repoID] == nil { + cache[repoID] = make(map[int64]*migrationActionRun) + } + cache[repoID][runIndex] = &run + return &run, nil +} + +func getJobIDByIndexCached(x *xorm.Engine, cache map[int64][]int64, runID, jobIndex int64) (int64, bool, error) { + jobIDs, ok := cache[runID] + if !ok { + var jobs []migrationActionRunJob + if err := x.Table("action_run_job").Where("run_id=?", runID).Asc("id").Cols("id").Find(&jobs); err != nil { + return 0, false, err + } + jobIDs = make([]int64, 0, len(jobs)) + for _, job := range jobs { + jobIDs = append(jobIDs, job.ID) + } + cache[runID] = jobIDs + } + if jobIndex < 0 || jobIndex >= int64(len(jobIDs)) { + return 0, false, nil + } + return jobIDs[jobIndex], true, nil +} + +func parseTargetURL(targetURL, repoLink string) (runNum, jobNum int64, ok bool) { + prefix := repoLink + actionsRunPath + if !strings.HasPrefix(targetURL, prefix) { + return 0, 0, false + } + rest := targetURL[len(prefix):] + + parts := strings.Split(rest, "/") // expect: {run_num}/jobs/{job_num} + if len(parts) == 3 && parts[1] == "jobs" { + runNum, err1 := strconv.ParseInt(parts[0], 10, 64) + jobNum, err2 := strconv.ParseInt(parts[2], 10, 64) + if err1 != nil || err2 != nil { + return 0, 0, false + } + return runNum, jobNum, true + } + + return 0, 0, false +} diff --git a/models/migrations/v1_26/v326_test.go b/models/migrations/v1_26/v326_test.go new file mode 100644 index 0000000000..ddc2640160 --- /dev/null +++ b/models/migrations/v1_26/v326_test.go @@ -0,0 +1,104 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_26 + +import ( + "testing" + + "code.gitea.io/gitea/models/migrations/base" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" + + _ "code.gitea.io/gitea/models/actions" + _ "code.gitea.io/gitea/models/git" + _ "code.gitea.io/gitea/models/repo" + + "github.com/stretchr/testify/require" + "xorm.io/xorm" +) + +func Test_FixCommitStatusTargetURLToUseRunAndJobID(t *testing.T) { + defer test.MockVariableValue(&setting.AppSubURL, "")() + + type Repository struct { + ID int64 `xorm:"pk autoincr"` + OwnerName string + Name string + } + + type ActionRun struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"index"` + Index int64 + } + + type ActionRunJob struct { + ID int64 `xorm:"pk autoincr"` + RunID int64 `xorm:"index"` + } + + type CommitStatus struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"index"` + TargetURL string + } + + type CommitStatusSummary struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"index"` + SHA string `xorm:"VARCHAR(64) NOT NULL"` + State string `xorm:"VARCHAR(7) NOT NULL"` + TargetURL string + } + + x, deferable := base.PrepareTestEnv(t, 0, + new(Repository), + new(ActionRun), + new(ActionRunJob), + new(CommitStatus), + new(CommitStatusSummary), + ) + defer deferable() + + newURL1 := "/testuser/repo1/actions/runs/106/jobs/530" + newURL2 := "/testuser/repo1/actions/runs/106/jobs/531" + + invalidWrongRepo := "/otheruser/badrepo/actions/runs/7/jobs/0" + invalidNonexistentRun := "/testuser/repo1/actions/runs/10/jobs/0" + invalidNonexistentJob := "/testuser/repo1/actions/runs/7/jobs/3" + externalTargetURL := "https://ci.example.com/build/123" + + require.NoError(t, FixCommitStatusTargetURLToUseRunAndJobID(x)) + + cases := []struct { + table string + id int64 + want string + }{ + {table: "commit_status", id: 10, want: newURL1}, + {table: "commit_status", id: 11, want: newURL2}, + {table: "commit_status", id: 12, want: invalidWrongRepo}, + {table: "commit_status", id: 13, want: invalidNonexistentRun}, + {table: "commit_status", id: 14, want: invalidNonexistentJob}, + {table: "commit_status", id: 15, want: externalTargetURL}, + {table: "commit_status_summary", id: 20, want: newURL1}, + {table: "commit_status_summary", id: 21, want: externalTargetURL}, + } + + for _, tc := range cases { + assertTargetURL(t, x, tc.table, tc.id, tc.want) + } +} + +func assertTargetURL(t *testing.T, x *xorm.Engine, table string, id int64, want string) { + t.Helper() + + var row struct { + TargetURL string + } + has, err := x.Table(table).Where("id=?", id).Cols("target_url").Get(&row) + require.NoError(t, err) + require.Truef(t, has, "row not found: table=%s id=%d", table, id) + require.Equal(t, want, row.TargetURL) +} diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index 6f4d5d3572..2d28e7ae86 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -1041,15 +1041,9 @@ func ActionsDispatchWorkflow(ctx *context.APIContext) { return } - workflowRun, err := actions_model.GetRunByRepoAndID(ctx, ctx.Repo.Repository.ID, runID) - if err != nil { - ctx.APIErrorInternal(err) - return - } - ctx.JSON(http.StatusOK, &api.RunDetails{ WorkflowRunID: runID, - HTMLURL: fmt.Sprintf("%s/actions/runs/%d", ctx.Repo.Repository.HTMLURL(ctx), workflowRun.Index), + HTMLURL: fmt.Sprintf("%s/actions/runs/%d", ctx.Repo.Repository.HTMLURL(ctx), runID), RunURL: fmt.Sprintf("%s/actions/runs/%d", ctx.Repo.Repository.APIURL(), runID), }) } diff --git a/routers/api/v1/repo/actions_run.go b/routers/api/v1/repo/actions_run.go index a12a6fdd6d..64ac1a3ad5 100644 --- a/routers/api/v1/repo/actions_run.go +++ b/routers/api/v1/repo/actions_run.go @@ -43,9 +43,13 @@ func DownloadActionsRunJobLogs(ctx *context.APIContext) { // "$ref": "#/responses/notFound" jobID := ctx.PathParamInt64("job_id") - curJob, err := actions_model.GetRunJobByID(ctx, jobID) + curJob, err := actions_model.GetRunJobByRepoAndID(ctx, ctx.Repo.Repository.ID, jobID) if err != nil { - ctx.APIErrorInternal(err) + if errors.Is(err, util.ErrNotExist) { + ctx.APIErrorNotFound(err) + } else { + ctx.APIErrorInternal(err) + } return } if err = curJob.LoadRepo(ctx); err != nil { diff --git a/routers/common/actions.go b/routers/common/actions.go index a4eabb6ba2..39d2111f5a 100644 --- a/routers/common/actions.go +++ b/routers/common/actions.go @@ -14,18 +14,15 @@ import ( "code.gitea.io/gitea/services/context" ) -func DownloadActionsRunJobLogsWithIndex(ctx *context.Base, ctxRepo *repo_model.Repository, runID, jobIndex int64) error { - runJobs, err := actions_model.GetRunJobsByRunID(ctx, runID) +func DownloadActionsRunJobLogsWithID(ctx *context.Base, ctxRepo *repo_model.Repository, runID, jobID int64) error { + job, err := actions_model.GetRunJobByRunAndID(ctx, runID, jobID) if err != nil { - return fmt.Errorf("GetRunJobsByRunID: %w", err) + return err } - if err = runJobs.LoadRepos(ctx); err != nil { - return fmt.Errorf("LoadRepos: %w", err) + if err := job.LoadRepo(ctx); err != nil { + return fmt.Errorf("LoadRepo: %w", err) } - if jobIndex < 0 || jobIndex >= int64(len(runJobs)) { - return util.NewNotExistErrorf("job index is out of range: %d", jobIndex) - } - return DownloadActionsRunJobLogs(ctx, ctxRepo, runJobs[jobIndex]) + return DownloadActionsRunJobLogs(ctx, ctxRepo, job) } func DownloadActionsRunJobLogs(ctx *context.Base, ctxRepo *repo_model.Repository, curJob *actions_model.ActionRunJob) error { diff --git a/routers/web/devtest/mock_actions.go b/routers/web/devtest/mock_actions.go index 7a71dad804..0dd33425dc 100644 --- a/routers/web/devtest/mock_actions.go +++ b/routers/web/devtest/mock_actions.go @@ -59,8 +59,8 @@ func generateMockStepsLog(logCur actions.LogCursor, opts generateMockStepsLogOpt } func MockActionsView(ctx *context.Context) { - ctx.Data["RunIndex"] = ctx.PathParam("run") - ctx.Data["JobIndex"] = ctx.PathParam("job") + ctx.Data["RunID"] = ctx.PathParam("run") + ctx.Data["JobID"] = ctx.PathParam("job") ctx.HTML(http.StatusOK, "devtest/repo-action-view") } diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 0eaa6cab41..2685dd8857 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -38,11 +38,11 @@ import ( "github.com/nektos/act/pkg/model" ) -func getRunIndex(ctx *context_module.Context) int64 { - // if run param is "latest", get the latest run index +func getRunID(ctx *context_module.Context) int64 { + // if run param is "latest", get the latest run id if ctx.PathParam("run") == "latest" { if run, _ := actions_model.GetLatestRun(ctx, ctx.Repo.Repository.ID); run != nil { - return run.Index + return run.ID } } return ctx.PathParamInt64("run") @@ -50,24 +50,25 @@ func getRunIndex(ctx *context_module.Context) int64 { func View(ctx *context_module.Context) { ctx.Data["PageIsActions"] = true - runIndex := getRunIndex(ctx) - jobIndex := ctx.PathParamInt("job") - ctx.Data["RunIndex"] = runIndex - ctx.Data["JobIndex"] = jobIndex - ctx.Data["ActionsURL"] = ctx.Repo.RepoLink + "/actions" + runID := getRunID(ctx) - if getRunJobs(ctx, runIndex, jobIndex); ctx.Written() { + _, _, current := getRunJobsAndCurrentJob(ctx, runID) + if ctx.Written() { return } + ctx.Data["RunID"] = runID + ctx.Data["JobID"] = current.ID + ctx.Data["ActionsURL"] = ctx.Repo.RepoLink + "/actions" + ctx.HTML(http.StatusOK, tplViewActions) } func ViewWorkflowFile(ctx *context_module.Context) { - runIndex := getRunIndex(ctx) - run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex) + runID := getRunID(ctx) + run, err := actions_model.GetRunByRepoAndID(ctx, ctx.Repo.Repository.ID, runID) if err != nil { - ctx.NotFoundOrServerError("GetRunByIndex", func(err error) bool { + ctx.NotFoundOrServerError("GetRunByRepoAndID", func(err error) bool { return errors.Is(err, util.ErrNotExist) }, err) return @@ -187,8 +188,8 @@ type ViewStepLogLine struct { Timestamp float64 `json:"timestamp"` } -func getActionsViewArtifacts(ctx context.Context, repoID, runIndex int64) (artifactsViewItems []*ArtifactsViewItem, err error) { - run, err := actions_model.GetRunByIndex(ctx, repoID, runIndex) +func getActionsViewArtifacts(ctx context.Context, repoID, runID int64) (artifactsViewItems []*ArtifactsViewItem, err error) { + run, err := actions_model.GetRunByRepoAndID(ctx, repoID, runID) if err != nil { return nil, err } @@ -208,14 +209,12 @@ func getActionsViewArtifacts(ctx context.Context, repoID, runIndex int64) (artif func ViewPost(ctx *context_module.Context) { req := web.GetForm(ctx).(*ViewRequest) - runIndex := getRunIndex(ctx) - jobIndex := ctx.PathParamInt("job") + runID := getRunID(ctx) - current, jobs := getRunJobs(ctx, runIndex, jobIndex) + run, jobs, current := getRunJobsAndCurrentJob(ctx, runID) if ctx.Written() { return } - run := current.Run if err := run.LoadAttributes(ctx); err != nil { ctx.ServerError("run.LoadAttributes", err) return @@ -223,7 +222,7 @@ func ViewPost(ctx *context_module.Context) { var err error resp := &ViewResponse{} - resp.Artifacts, err = getActionsViewArtifacts(ctx, ctx.Repo.Repository.ID, runIndex) + resp.Artifacts, err = getActionsViewArtifacts(ctx, ctx.Repo.Repository.ID, runID) if err != nil { if !errors.Is(err, util.ErrNotExist) { ctx.ServerError("getActionsViewArtifacts", err) @@ -400,15 +399,12 @@ func convertToViewModel(ctx context.Context, locale translation.Locale, cursors } // Rerun will rerun jobs in the given run -// If jobIndexStr is a blank string, it means rerun all jobs +// If jobIDStr is a blank string, it means rerun all jobs func Rerun(ctx *context_module.Context) { - runIndex := getRunIndex(ctx) - jobIndexHas := ctx.PathParam("job") != "" - jobIndex := ctx.PathParamInt("job") + runID := getRunID(ctx) - run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex) - if err != nil { - ctx.ServerError("GetRunByIndex", err) + run, jobs, currentJob := getRunJobsAndCurrentJob(ctx, runID) + if ctx.Written() { return } @@ -426,19 +422,9 @@ func Rerun(ctx *context_module.Context) { return } - jobs, err := actions_model.GetRunJobsByRunID(ctx, run.ID) - if err != nil { - ctx.ServerError("GetRunJobsByRunID", err) - return - } - var targetJob *actions_model.ActionRunJob // nil means rerun all jobs - if jobIndexHas { - if jobIndex < 0 || jobIndex >= len(jobs) { - ctx.JSONError(ctx.Locale.Tr("error.not_found")) - return - } - targetJob = jobs[jobIndex] // only rerun the selected job + if ctx.PathParam("job") != "" { + targetJob = currentJob } if err := actions_service.RerunWorkflowRunJobs(ctx, ctx.Repo.Repository, run, jobs, targetJob); err != nil { @@ -450,28 +436,28 @@ func Rerun(ctx *context_module.Context) { } func Logs(ctx *context_module.Context) { - runIndex := getRunIndex(ctx) - jobIndex := ctx.PathParamInt64("job") + runID := getRunID(ctx) + jobID := ctx.PathParamInt64("job") - run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex) + run, err := actions_model.GetRunByRepoAndID(ctx, ctx.Repo.Repository.ID, runID) if err != nil { - ctx.NotFoundOrServerError("GetRunByIndex", func(err error) bool { + ctx.NotFoundOrServerError("GetRunByRepoAndID", func(err error) bool { return errors.Is(err, util.ErrNotExist) }, err) return } - if err = common.DownloadActionsRunJobLogsWithIndex(ctx.Base, ctx.Repo.Repository, run.ID, jobIndex); err != nil { - ctx.NotFoundOrServerError("DownloadActionsRunJobLogsWithIndex", func(err error) bool { + if err = common.DownloadActionsRunJobLogsWithID(ctx.Base, ctx.Repo.Repository, run.ID, jobID); err != nil { + ctx.NotFoundOrServerError("DownloadActionsRunJobLogsWithID", func(err error) bool { return errors.Is(err, util.ErrNotExist) }, err) } } func Cancel(ctx *context_module.Context) { - runIndex := getRunIndex(ctx) + runID := getRunID(ctx) - firstJob, jobs := getRunJobs(ctx, runIndex, -1) + run, jobs, _ := getRunJobsAndCurrentJob(ctx, runID) if ctx.Written() { return } @@ -490,7 +476,7 @@ func Cancel(ctx *context_module.Context) { return } - actions_service.CreateCommitStatusForRunJobs(ctx, firstJob.Run, jobs...) + actions_service.CreateCommitStatusForRunJobs(ctx, run, jobs...) actions_service.EmitJobsIfReadyByJobs(updatedJobs) for _, job := range updatedJobs { @@ -505,9 +491,9 @@ func Cancel(ctx *context_module.Context) { } func Approve(ctx *context_module.Context) { - runIndex := getRunIndex(ctx) + runID := getRunID(ctx) - approveRuns(ctx, []int64{runIndex}) + approveRuns(ctx, []int64{runID}) if ctx.Written() { return } @@ -515,17 +501,17 @@ func Approve(ctx *context_module.Context) { ctx.JSONOK() } -func approveRuns(ctx *context_module.Context, runIndexes []int64) { +func approveRuns(ctx *context_module.Context, runIDs []int64) { doer := ctx.Doer repo := ctx.Repo.Repository updatedJobs := make([]*actions_model.ActionRunJob, 0) - runMap := make(map[int64]*actions_model.ActionRun, len(runIndexes)) - runJobs := make(map[int64][]*actions_model.ActionRunJob, len(runIndexes)) + runMap := make(map[int64]*actions_model.ActionRun, len(runIDs)) + runJobs := make(map[int64][]*actions_model.ActionRunJob, len(runIDs)) err := db.WithTx(ctx, func(ctx context.Context) (err error) { - for _, runIndex := range runIndexes { - run, err := actions_model.GetRunByIndex(ctx, repo.ID, runIndex) + for _, runID := range runIDs { + run, err := actions_model.GetRunByRepoAndID(ctx, repo.ID, runID) if err != nil { return err } @@ -560,7 +546,9 @@ func approveRuns(ctx *context_module.Context, runIndexes []int64) { return nil }) if err != nil { - ctx.ServerError("UpdateRunJob", err) + ctx.NotFoundOrServerError("approveRuns", func(err error) bool { + return errors.Is(err, util.ErrNotExist) + }, err) return } @@ -580,16 +568,16 @@ func approveRuns(ctx *context_module.Context, runIndexes []int64) { } func Delete(ctx *context_module.Context) { - runIndex := getRunIndex(ctx) + runID := getRunID(ctx) repoID := ctx.Repo.Repository.ID - run, err := actions_model.GetRunByIndex(ctx, repoID, runIndex) + run, err := actions_model.GetRunByRepoAndID(ctx, repoID, runID) if err != nil { if errors.Is(err, util.ErrNotExist) { ctx.JSONErrorNotFound() return } - ctx.ServerError("GetRunByIndex", err) + ctx.ServerError("GetRunByRepoAndID", err) return } @@ -606,47 +594,54 @@ func Delete(ctx *context_module.Context) { ctx.JSONOK() } -// getRunJobs gets the jobs of runIndex, and returns jobs[jobIndex], jobs. -// Any error will be written to the ctx. -// It never returns a nil job of an empty jobs, if the jobIndex is out of range, it will be treated as 0. -func getRunJobs(ctx *context_module.Context, runIndex int64, jobIndex int) (*actions_model.ActionRunJob, []*actions_model.ActionRunJob) { - run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex) +// getRunJobsAndCurrentJob loads the run and its jobs for runID, and returns the selected job based on the optional "job" path param (or the first job by default). +// Any error will be written to the ctx, and nils are returned in that case. +func getRunJobsAndCurrentJob(ctx *context_module.Context, runID int64) (*actions_model.ActionRun, []*actions_model.ActionRunJob, *actions_model.ActionRunJob) { + run, err := actions_model.GetRunByRepoAndID(ctx, ctx.Repo.Repository.ID, runID) if err != nil { - if errors.Is(err, util.ErrNotExist) { - ctx.NotFound(nil) - return nil, nil - } - ctx.ServerError("GetRunByIndex", err) - return nil, nil + ctx.NotFoundOrServerError("GetRunByRepoAndID", func(err error) bool { + return errors.Is(err, util.ErrNotExist) + }, err) + return nil, nil, nil } run.Repo = ctx.Repo.Repository jobs, err := actions_model.GetRunJobsByRunID(ctx, run.ID) if err != nil { ctx.ServerError("GetRunJobsByRunID", err) - return nil, nil + return nil, nil, nil } if len(jobs) == 0 { ctx.NotFound(nil) - return nil, nil + return nil, nil, nil } - for _, v := range jobs { - v.Run = run + for _, job := range jobs { + job.Run = run } - if jobIndex >= 0 && jobIndex < len(jobs) { - return jobs[jobIndex], jobs + current := jobs[0] + if ctx.PathParam("job") != "" { + jobID := ctx.PathParamInt64("job") + current, err = actions_model.GetRunJobByRunAndID(ctx, run.ID, jobID) + if err != nil { + ctx.NotFoundOrServerError("GetRunJobByRunAndID", func(err error) bool { + return errors.Is(err, util.ErrNotExist) + }, err) + return nil, nil, nil + } + current.Run = run } - return jobs[0], jobs + + return run, jobs, current } func ArtifactsDeleteView(ctx *context_module.Context) { - runIndex := getRunIndex(ctx) + runID := getRunID(ctx) artifactName := ctx.PathParam("artifact_name") - run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex) + run, err := actions_model.GetRunByRepoAndID(ctx, ctx.Repo.Repository.ID, runID) if err != nil { - ctx.NotFoundOrServerError("GetRunByIndex", func(err error) bool { + ctx.NotFoundOrServerError("GetRunByRepoAndID", func(err error) bool { return errors.Is(err, util.ErrNotExist) }, err) return @@ -659,16 +654,16 @@ func ArtifactsDeleteView(ctx *context_module.Context) { } func ArtifactsDownloadView(ctx *context_module.Context) { - runIndex := getRunIndex(ctx) + runID := getRunID(ctx) artifactName := ctx.PathParam("artifact_name") - run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex) + run, err := actions_model.GetRunByRepoAndID(ctx, ctx.Repo.Repository.ID, runID) if err != nil { if errors.Is(err, util.ErrNotExist) { ctx.HTTPError(http.StatusNotFound, err.Error()) return } - ctx.ServerError("GetRunByIndex", err) + ctx.ServerError("GetRunByRepoAndID", err) return } @@ -754,19 +749,19 @@ func ApproveAllChecks(ctx *context_module.Context) { return } - runIndexes := make([]int64, 0, len(runs)) + runIDs := make([]int64, 0, len(runs)) for _, run := range runs { if run.NeedApproval { - runIndexes = append(runIndexes, run.Index) + runIDs = append(runIDs, run.ID) } } - if len(runIndexes) == 0 { + if len(runIDs) == 0 { ctx.JSONOK() return } - approveRuns(ctx, runIndexes) + approveRuns(ctx, runIDs) if ctx.Written() { return } diff --git a/services/actions/commit_status.go b/services/actions/commit_status.go index 22ee8ad1d6..95b848f4fb 100644 --- a/services/actions/commit_status.go +++ b/services/actions/commit_status.go @@ -56,21 +56,21 @@ func CreateCommitStatusForRunJobs(ctx context.Context, run *actions_model.Action func GetRunsFromCommitStatuses(ctx context.Context, statuses []*git_model.CommitStatus) ([]*actions_model.ActionRun, error) { runMap := make(map[int64]*actions_model.ActionRun) for _, status := range statuses { - runIndex, _, ok := status.ParseGiteaActionsTargetURL(ctx) + runID, _, ok := status.ParseGiteaActionsTargetURL(ctx) if !ok { continue } - _, ok = runMap[runIndex] + _, ok = runMap[runID] if !ok { - run, err := actions_model.GetRunByIndex(ctx, status.RepoID, runIndex) + run, err := actions_model.GetRunByRepoAndID(ctx, status.RepoID, runID) if err != nil { if errors.Is(err, util.ErrNotExist) { // the run may be deleted manually, just skip it continue } - return nil, fmt.Errorf("GetRunByIndex: %w", err) + return nil, fmt.Errorf("GetRunByRepoAndID: %w", err) } - runMap[runIndex] = run + runMap[runID] = run } } runs := make([]*actions_model.ActionRun, 0, len(runMap)) @@ -181,15 +181,10 @@ func createCommitStatus(ctx context.Context, repo *repo_model.Repository, event, description = "Unknown status: " + strconv.Itoa(int(job.Status)) } - index, err := getIndexOfJob(ctx, job) - if err != nil { - return fmt.Errorf("getIndexOfJob: %w", err) - } - creator := user_model.NewActionsUser() status := git_model.CommitStatus{ SHA: commitID, - TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), index), + TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), job.ID), Description: description, Context: ctxName, CreatorID: creator.ID, @@ -213,17 +208,3 @@ func toCommitStatus(status actions_model.Status) commitstatus.CommitStatusState return commitstatus.CommitStatusError } } - -func getIndexOfJob(ctx context.Context, job *actions_model.ActionRunJob) (int, error) { - // TODO: store job index as a field in ActionRunJob to avoid this - jobs, err := actions_model.GetRunJobsByRunID(ctx, job.RunID) - if err != nil { - return 0, err - } - for i, v := range jobs { - if v.ID == job.ID { - return i, nil - } - } - return 0, nil -} diff --git a/services/actions/rerun.go b/services/actions/rerun.go index 277da39b82..5177b90d61 100644 --- a/services/actions/rerun.go +++ b/services/actions/rerun.go @@ -148,6 +148,9 @@ func rerunWorkflowJob(ctx context.Context, job *actions_model.ActionRunJob, shou if err := job.LoadRun(ctx); err != nil { return err } + if err := job.Run.LoadAttributes(ctx); err != nil { + return err + } vars, err := actions_model.GetVariablesOfRun(ctx, job.Run) if err != nil { diff --git a/services/convert/convert.go b/services/convert/convert.go index 391960b369..8bef63f7cd 100644 --- a/services/convert/convert.go +++ b/services/convert/convert.go @@ -324,18 +324,6 @@ func ToActionWorkflowJob(ctx context.Context, repo *repo_model.Repository, task return nil, err } - jobIndex := 0 - jobs, err := actions_model.GetRunJobsByRunID(ctx, job.RunID) - if err != nil { - return nil, err - } - for i, j := range jobs { - if j.ID == job.ID { - jobIndex = i - break - } - } - status, conclusion := ToActionsStatus(job.Status) var runnerID int64 var runnerName string @@ -379,7 +367,7 @@ func ToActionWorkflowJob(ctx context.Context, repo *repo_model.Repository, task ID: job.ID, // missing api endpoint for this location URL: fmt.Sprintf("%s/actions/jobs/%d", repo.APIURL(), job.ID), - HTMLURL: fmt.Sprintf("%s/jobs/%d", job.Run.HTMLURL(), jobIndex), + HTMLURL: fmt.Sprintf("%s/jobs/%d", job.Run.HTMLURL(), job.ID), RunID: job.RunID, // Missing api endpoint for this location, artifacts are available under a nested url RunURL: fmt.Sprintf("%s/actions/runs/%d", repo.APIURL(), job.RunID), diff --git a/templates/devtest/repo-action-view.tmpl b/templates/devtest/repo-action-view.tmpl index 292c84c928..b3a52db1e2 100644 --- a/templates/devtest/repo-action-view.tmpl +++ b/templates/devtest/repo-action-view.tmpl @@ -6,8 +6,8 @@ Run:CanRerun {{template "repo/actions/view_component" (dict - "RunIndex" (or .RunIndex 10) - "JobIndex" (or .JobIndex 0) + "RunID" (or .RunID 10) + "JobID" (or .JobID 0) "ActionsURL" (print AppSubUrl "/devtest/actions-mock") )}} diff --git a/templates/repo/actions/view.tmpl b/templates/repo/actions/view.tmpl index bde579f882..1eb84a9b93 100644 --- a/templates/repo/actions/view.tmpl +++ b/templates/repo/actions/view.tmpl @@ -3,8 +3,8 @@
{{template "repo/header" .}} {{template "repo/actions/view_component" (dict - "RunIndex" .RunIndex - "JobIndex" .JobIndex + "RunID" .RunID + "JobID" .JobID "ActionsURL" .ActionsURL )}}
diff --git a/templates/repo/actions/view_component.tmpl b/templates/repo/actions/view_component.tmpl index ebe5158c8a..457159ef54 100644 --- a/templates/repo/actions/view_component.tmpl +++ b/templates/repo/actions/view_component.tmpl @@ -1,6 +1,6 @@
>, @@ -366,7 +366,7 @@ export default defineComponent({ // for example: make cursor=null means the first time to fetch logs, cursor=eof means no more logs, etc return {step: idx, cursor: it.cursor, expanded: it.expanded}; }); - const resp = await POST(`${this.actionsURL}/runs/${this.runIndex}/jobs/${this.jobIndex}`, { + const resp = await POST(`${this.actionsURL}/runs/${this.runId}/jobs/${this.jobId}`, { signal: abortController.signal, data: {logCursors}, }); @@ -538,13 +538,13 @@ export default defineComponent({
- +
{{ job.name }}
- + {{ job.duration }}
@@ -581,7 +581,7 @@ export default defineComponent({
- + {{ locale.downloadLogs }} diff --git a/web_src/js/components/WorkflowGraph.vue b/web_src/js/components/WorkflowGraph.vue index dc876d9437..571db2cd03 100644 --- a/web_src/js/components/WorkflowGraph.vue +++ b/web_src/js/components/WorkflowGraph.vue @@ -40,7 +40,7 @@ interface StoredState { const props = defineProps<{ jobs: ActionsJob[]; - currentJobIndex: number; + currentJobId: number; runLink: string; workflowId: string; }>() @@ -588,9 +588,9 @@ function computeJobLevels(jobs: ActionsJob[]): Map { } function onNodeClick(job: JobNode, event: MouseEvent) { - if (job.index === props.currentJobIndex) return; + if (job.id === props.currentJobId) return; - const link = `${props.runLink}/jobs/${job.index}`; + const link = `${props.runLink}/jobs/${job.id}`; if (event.ctrlKey || event.metaKey) { window.open(link, '_blank'); return; @@ -652,7 +652,7 @@ function onNodeClick(job: JobNode, event: MouseEvent) { diff --git a/web_src/js/features/repo-actions.ts b/web_src/js/features/repo-actions.ts index 242dd30016..fca41c0c66 100644 --- a/web_src/js/features/repo-actions.ts +++ b/web_src/js/features/repo-actions.ts @@ -11,8 +11,8 @@ export function initRepositoryActionView() { if (parentFullHeight) parentFullHeight.classList.add('tw-pb-0'); const view = createApp(RepoActionView, { - runIndex: parseInt(el.getAttribute('data-run-index')!), - jobIndex: parseInt(el.getAttribute('data-job-index')!), + runId: parseInt(el.getAttribute('data-run-id')!), + jobId: parseInt(el.getAttribute('data-job-id')!), actionsURL: el.getAttribute('data-actions-url'), locale: { approve: el.getAttribute('data-locale-approve'),