mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-05-27 04:07:08 +00:00
Actions Artifacts support uploading multiple files and directories (#24874)
current actions artifacts implementation only support single file artifact. To support multiple files uploading, it needs: - save each file to each db record with same run-id, same artifact-name and proper artifact-path - need change artifact uploading url without artifact-id, multiple files creates multiple artifact-ids - support `path` in download-artifact action. artifact should download to `{path}/{artifact-path}`. - in repo action view, it provides zip download link in artifacts list in summary page, no matter this artifact contains single or multiple files.
This commit is contained in:
parent
3acaaa29dd
commit
f3d293d2bb
10 changed files with 644 additions and 354 deletions
82
routers/api/actions/artifacts_utils.go
Normal file
82
routers/api/actions/artifacts_utils.go
Normal file
|
@ -0,0 +1,82 @@
|
|||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/actions"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
const (
|
||||
artifactXTfsFileLengthHeader = "x-tfs-filelength"
|
||||
artifactXActionsResultsMD5Header = "x-actions-results-md5"
|
||||
)
|
||||
|
||||
// The rules are from https://github.com/actions/toolkit/blob/main/packages/artifact/src/internal/path-and-artifact-name-validation.ts#L32
|
||||
var invalidArtifactNameChars = strings.Join([]string{"\\", "/", "\"", ":", "<", ">", "|", "*", "?", "\r", "\n"}, "")
|
||||
|
||||
func validateArtifactName(ctx *ArtifactContext, artifactName string) bool {
|
||||
if strings.ContainsAny(artifactName, invalidArtifactNameChars) {
|
||||
log.Error("Error checking artifact name contains invalid character")
|
||||
ctx.Error(http.StatusBadRequest, "Error checking artifact name contains invalid character")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func validateRunID(ctx *ArtifactContext) (*actions.ActionTask, int64, bool) {
|
||||
task := ctx.ActionTask
|
||||
runID := ctx.ParamsInt64("run_id")
|
||||
if task.Job.RunID != runID {
|
||||
log.Error("Error runID not match")
|
||||
ctx.Error(http.StatusBadRequest, "run-id does not match")
|
||||
return nil, 0, false
|
||||
}
|
||||
return task, runID, true
|
||||
}
|
||||
|
||||
func validateArtifactHash(ctx *ArtifactContext, artifactName string) bool {
|
||||
paramHash := ctx.Params("artifact_hash")
|
||||
// use artifact name to create upload url
|
||||
artifactHash := fmt.Sprintf("%x", md5.Sum([]byte(artifactName)))
|
||||
if paramHash == artifactHash {
|
||||
return true
|
||||
}
|
||||
log.Error("Invalid artifact hash: %s", paramHash)
|
||||
ctx.Error(http.StatusBadRequest, "Invalid artifact hash")
|
||||
return false
|
||||
}
|
||||
|
||||
func parseArtifactItemPath(ctx *ArtifactContext) (string, string, bool) {
|
||||
// itemPath is generated from upload-artifact action
|
||||
// it's formatted as {artifact_name}/{artfict_path_in_runner}
|
||||
itemPath := util.PathJoinRel(ctx.Req.URL.Query().Get("itemPath"))
|
||||
artifactName := strings.Split(itemPath, "/")[0]
|
||||
artifactPath := strings.TrimPrefix(itemPath, artifactName+"/")
|
||||
if !validateArtifactHash(ctx, artifactName) {
|
||||
return "", "", false
|
||||
}
|
||||
if !validateArtifactName(ctx, artifactName) {
|
||||
return "", "", false
|
||||
}
|
||||
return artifactName, artifactPath, true
|
||||
}
|
||||
|
||||
// getUploadFileSize returns the size of the file to be uploaded.
|
||||
// The raw size is the size of the file as reported by the header X-TFS-FileLength.
|
||||
func getUploadFileSize(ctx *ArtifactContext) (int64, int64, error) {
|
||||
contentLength := ctx.Req.ContentLength
|
||||
xTfsLength, _ := strconv.ParseInt(ctx.Req.Header.Get(artifactXTfsFileLengthHeader), 10, 64)
|
||||
if xTfsLength > 0 {
|
||||
return xTfsLength, contentLength, nil
|
||||
}
|
||||
return contentLength, contentLength, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue