feat(actions): Add artifact preview in Actions run view (#36754)

Closes https://github.com/go-gitea/gitea/issues/33579.

Adds browser previews for Actions artifacts. Selecting an artifact opens
its file browser; selecting a file renders it in the same tab. The ZIP
download remains available separately.

Previews require sign-in and read access to the run. Text, image and PDF
files are supported; rendered HTML and JavaScript run in a sandboxed
frame and are labeled as automatically generated. The frame loads files
from a signed link that expires after an hour, because its requests
carry no session cookie. `[actions] ARTIFACT_PREVIEW_MAX_SIZE` limits
total previewable artifact size (`0` disables previews; `-1` removes the
limit); individual files also follow `[ui] MAX_DISPLAY_FILE_SIZE`.

<img width="1803" height="913" alt="image"
src="https://github.com/user-attachments/assets/a38fd704-2244-44fa-9181-c695ecbe0276"
/>

Docs: https://gitea.com/gitea/docs/pulls/533

---------

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
This commit is contained in:
bircni
2026-09-26 09:42:36 +02:00
committed by GitHub
parent 857d3d3df3
commit 5a56e118e4
22 changed files with 971 additions and 68 deletions
+5 -2
View File
@@ -210,8 +210,11 @@ func keepLatestAttemptArtifacts(arts []*ActionArtifact) []*ActionArtifact {
})
}
// ActionArtifactMeta is the meta-data of an artifact
// ActionArtifactMeta is the metadata of an artifact
type ActionArtifactMeta struct {
// The ID identifies the artifact group. The preview handler loads all files with the same run, attempt, and artifact name, then selects the requested file by path.
// It is the lowest row ID in the group query, legacy artifacts have one row per file.
ID int64
ArtifactName string
FileSize int64
Status ArtifactStatus
@@ -225,7 +228,7 @@ func ListUploadedArtifactsMetaByRunAttempt(ctx context.Context, repoID, runID, r
return arts, db.GetEngine(ctx).Table("action_artifact").
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").
Select("min(id) as id, artifact_name, sum(file_size) as file_size, max(status) as status, max(expired_unix) as expired_unix").
Find(&arts)
}