Files
gitea-mirror/routers/common/actions.go
Zettat123 385994295d Replace index with id in actions routes (#36842)
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 <zettat123@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-10 22:14:48 +01:00

69 lines
1.8 KiB
Go

// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package common
import (
"fmt"
"strings"
actions_model "code.gitea.io/gitea/models/actions"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/context"
)
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 err
}
if err := job.LoadRepo(ctx); err != nil {
return fmt.Errorf("LoadRepo: %w", err)
}
return DownloadActionsRunJobLogs(ctx, ctxRepo, job)
}
func DownloadActionsRunJobLogs(ctx *context.Base, ctxRepo *repo_model.Repository, curJob *actions_model.ActionRunJob) error {
if curJob.Repo.ID != ctxRepo.ID {
return util.NewNotExistErrorf("job not found")
}
if curJob.TaskID == 0 {
return util.NewNotExistErrorf("job not started")
}
if err := curJob.LoadRun(ctx); err != nil {
return fmt.Errorf("LoadRun: %w", err)
}
task, err := actions_model.GetTaskByID(ctx, curJob.TaskID)
if err != nil {
return fmt.Errorf("GetTaskByID: %w", err)
}
if task.LogExpired {
return util.NewNotExistErrorf("logs have been cleaned up")
}
reader, err := actions.OpenLogs(ctx, task.LogInStorage, task.LogFilename)
if err != nil {
return fmt.Errorf("OpenLogs: %w", err)
}
defer reader.Close()
workflowName := curJob.Run.WorkflowID
if p := strings.Index(workflowName, "."); p > 0 {
workflowName = workflowName[0:p]
}
ctx.ServeContent(reader, &context.ServeHeaderOptions{
Filename: fmt.Sprintf("%v-%v-%v.log", workflowName, curJob.Name, task.ID),
ContentLength: &task.LogSize,
ContentType: "text/plain",
ContentTypeCharset: "utf-8",
Disposition: "attachment",
})
return nil
}