Artifact deletion in actions ui (#27172)

Add deletion link in runs view page.
Fix #26315

![image](aa65a4ab-f434-4deb-b953-21e63c212033)

When click deletion button. It marks this artifact `need-delete`.

This artifact would be deleted when actions cleanup cron task.
This commit is contained in:
FuXiaoHei 2024-02-18 18:33:50 +08:00 committed by Gergely Nagy
parent c47e6ceb82
commit c551d3f3ab
No known key found for this signature in database
8 changed files with 120 additions and 11 deletions

View file

@ -98,15 +98,16 @@ type ViewRequest struct {
type ViewResponse struct {
State struct {
Run struct {
Link string `json:"link"`
Title string `json:"title"`
Status string `json:"status"`
CanCancel bool `json:"canCancel"`
CanApprove bool `json:"canApprove"` // the run needs an approval and the doer has permission to approve
CanRerun bool `json:"canRerun"`
Done bool `json:"done"`
Jobs []*ViewJob `json:"jobs"`
Commit ViewCommit `json:"commit"`
Link string `json:"link"`
Title string `json:"title"`
Status string `json:"status"`
CanCancel bool `json:"canCancel"`
CanApprove bool `json:"canApprove"` // the run needs an approval and the doer has permission to approve
CanRerun bool `json:"canRerun"`
CanDeleteArtifact bool `json:"canDeleteArtifact"`
Done bool `json:"done"`
Jobs []*ViewJob `json:"jobs"`
Commit ViewCommit `json:"commit"`
} `json:"run"`
CurrentJob struct {
Title string `json:"title"`
@ -187,6 +188,7 @@ func ViewPost(ctx *context_module.Context) {
resp.State.Run.CanCancel = !run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions)
resp.State.Run.CanApprove = run.NeedApproval && ctx.Repo.CanWrite(unit.TypeActions)
resp.State.Run.CanRerun = run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions)
resp.State.Run.CanDeleteArtifact = run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions)
resp.State.Run.Done = run.Status.IsDone()
resp.State.Run.Jobs = make([]*ViewJob, 0, len(jobs)) // marshal to '[]' instead fo 'null' in json
resp.State.Run.Status = run.Status.String()
@ -576,6 +578,29 @@ func ArtifactsView(ctx *context_module.Context) {
ctx.JSON(http.StatusOK, artifactsResponse)
}
func ArtifactsDeleteView(ctx *context_module.Context) {
if !ctx.Repo.CanWrite(unit.TypeActions) {
ctx.Error(http.StatusForbidden, "no permission")
return
}
runIndex := ctx.ParamsInt64("run")
artifactName := ctx.Params("artifact_name")
run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex)
if err != nil {
ctx.NotFoundOrServerError("GetRunByIndex", func(err error) bool {
return errors.Is(err, util.ErrNotExist)
}, err)
return
}
if err = actions_model.SetArtifactNeedDelete(ctx, run.ID, artifactName); err != nil {
ctx.Error(http.StatusInternalServerError, err.Error())
return
}
ctx.JSON(http.StatusOK, struct{}{})
}
func ArtifactsDownloadView(ctx *context_module.Context) {
runIndex := ctx.ParamsInt64("run")
artifactName := ctx.Params("artifact_name")
@ -603,6 +628,14 @@ func ArtifactsDownloadView(ctx *context_module.Context) {
return
}
// if artifacts status is not uploaded-confirmed, treat it as not found
for _, art := range artifacts {
if art.Status != int64(actions_model.ArtifactStatusUploadConfirmed) {
ctx.Error(http.StatusNotFound, "artifact not found")
return
}
}
ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s.zip; filename*=UTF-8''%s.zip", url.PathEscape(artifactName), artifactName))
writer := zip.NewWriter(ctx.Resp)

View file

@ -1401,6 +1401,7 @@ func registerRoutes(m *web.Route) {
m.Post("/approve", reqRepoActionsWriter, actions.Approve)
m.Post("/artifacts", actions.ArtifactsView)
m.Get("/artifacts/{artifact_name}", actions.ArtifactsDownloadView)
m.Delete("/artifacts/{artifact_name}", actions.ArtifactsDeleteView)
m.Post("/rerun", reqRepoActionsWriter, actions.Rerun)
})
})