Implement actions artifacts (#22738)

Implement action artifacts server api.

This change is used for supporting
https://github.com/actions/upload-artifact and
https://github.com/actions/download-artifact in gitea actions. It can
run sample workflow from doc
https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts.
The api design is inspired by
https://github.com/nektos/act/blob/master/pkg/artifacts/server.go and
includes some changes from gitea internal structs and methods.

Actions artifacts contains two parts:

- Gitea server api and storage (this pr implement basic design without
some complex cases supports)
- Runner communicate with gitea server api (in comming)

Old pr https://github.com/go-gitea/gitea/pull/22345 is outdated after
actions merged. I create new pr from main branch.


![897f7694-3e0f-4f7c-bb4b-9936624ead45](https://user-images.githubusercontent.com/2142787/219382371-eb3cf810-e4e0-456b-a8ff-aecc2b1a1032.jpeg)

Add artifacts list in actions workflow page.
This commit is contained in:
FuXiaoHei 2023-05-19 21:37:57 +08:00 committed by GitHub
parent 7985cde84d
commit c757765a9e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1127 additions and 6 deletions

View file

@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/base"
context_module "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
@ -418,3 +419,80 @@ func getRunJobs(ctx *context_module.Context, runIndex, jobIndex int64) (*actions
}
return jobs[0], jobs
}
type ArtifactsViewResponse struct {
Artifacts []*ArtifactsViewItem `json:"artifacts"`
}
type ArtifactsViewItem struct {
Name string `json:"name"`
Size int64 `json:"size"`
ID int64 `json:"id"`
}
func ArtifactsView(ctx *context_module.Context) {
runIndex := ctx.ParamsInt64("run")
run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex)
if err != nil {
if errors.Is(err, util.ErrNotExist) {
ctx.Error(http.StatusNotFound, err.Error())
return
}
ctx.Error(http.StatusInternalServerError, err.Error())
return
}
artifacts, err := actions_model.ListUploadedArtifactsByRunID(ctx, run.ID)
if err != nil {
ctx.Error(http.StatusInternalServerError, err.Error())
return
}
artifactsResponse := ArtifactsViewResponse{
Artifacts: make([]*ArtifactsViewItem, 0, len(artifacts)),
}
for _, art := range artifacts {
artifactsResponse.Artifacts = append(artifactsResponse.Artifacts, &ArtifactsViewItem{
Name: art.ArtifactName,
Size: art.FileSize,
ID: art.ID,
})
}
ctx.JSON(http.StatusOK, artifactsResponse)
}
func ArtifactsDownloadView(ctx *context_module.Context) {
runIndex := ctx.ParamsInt64("run")
artifactID := ctx.ParamsInt64("id")
artifact, err := actions_model.GetArtifactByID(ctx, artifactID)
if errors.Is(err, util.ErrNotExist) {
ctx.Error(http.StatusNotFound, err.Error())
} else if err != nil {
ctx.Error(http.StatusInternalServerError, err.Error())
return
}
run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex)
if err != nil {
if errors.Is(err, util.ErrNotExist) {
ctx.Error(http.StatusNotFound, err.Error())
return
}
ctx.Error(http.StatusInternalServerError, err.Error())
return
}
if artifact.RunID != run.ID {
ctx.Error(http.StatusNotFound, "artifact not found")
return
}
f, err := storage.ActionsArtifacts.Open(artifact.StoragePath)
if err != nil {
ctx.Error(http.StatusInternalServerError, err.Error())
return
}
defer f.Close()
ctx.ServeContent(f, &context_module.ServeHeaderOptions{
Filename: artifact.ArtifactName,
LastModified: artifact.CreatedUnix.AsLocalTime(),
})
}