mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-21 03:23:26 +02:00
Merge remote-tracking branch 'upstream/main' into limit-repo-size
This commit is contained in:
@@ -97,7 +97,7 @@ func (s *Service) Register(
|
||||
// FetchTask assigns a task to the runner
|
||||
func (s *Service) FetchTask(
|
||||
ctx context.Context,
|
||||
req *connect.Request[runnerv1.FetchTaskRequest],
|
||||
_ *connect.Request[runnerv1.FetchTaskRequest],
|
||||
) (*connect.Response[runnerv1.FetchTaskResponse], error) {
|
||||
runner := GetRunner(ctx)
|
||||
|
||||
@@ -145,6 +145,31 @@ func (s *Service) UpdateTask(
|
||||
return nil, status.Errorf(codes.Internal, "update task: %v", err)
|
||||
}
|
||||
|
||||
for k, v := range req.Msg.Outputs {
|
||||
if len(k) > 255 {
|
||||
log.Warn("Ignore the output of task %d because the key is too long: %q", task.ID, k)
|
||||
continue
|
||||
}
|
||||
// The value can be a maximum of 1 MB
|
||||
if l := len(v); l > 1024*1024 {
|
||||
log.Warn("Ignore the output %q of task %d because the value is too long: %v", k, task.ID, l)
|
||||
continue
|
||||
}
|
||||
// There's another limitation on GitHub that the total of all outputs in a workflow run can be a maximum of 50 MB.
|
||||
// We don't check the total size here because it's not easy to do, and it doesn't really worth it.
|
||||
// See https://docs.github.com/en/actions/using-jobs/defining-outputs-for-jobs
|
||||
|
||||
if err := actions_model.InsertTaskOutputIfNotExist(ctx, task.ID, k, v); err != nil {
|
||||
log.Warn("Failed to insert the output %q of task %d: %v", k, task.ID, err)
|
||||
// It's ok not to return errors, the runner will resend the outputs.
|
||||
}
|
||||
}
|
||||
sentOutputs, err := actions_model.FindTaskOutputKeyByTaskID(ctx, task.ID)
|
||||
if err != nil {
|
||||
log.Warn("Failed to find the sent outputs of task %d: %v", task.ID, err)
|
||||
// It's not to return errors, it can be handled when the runner resends sent outputs.
|
||||
}
|
||||
|
||||
if err := task.LoadJob(ctx); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "load job: %v", err)
|
||||
}
|
||||
@@ -162,6 +187,7 @@ func (s *Service) UpdateTask(
|
||||
Id: req.Msg.State.Id,
|
||||
Result: task.Status.AsResult(),
|
||||
},
|
||||
SentOutputs: sentOutputs,
|
||||
}), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,17 @@ func pickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv
|
||||
Context: generateTaskContext(t),
|
||||
Secrets: getSecretsOfTask(ctx, t),
|
||||
}
|
||||
|
||||
if needs, err := findTaskNeeds(ctx, t); err != nil {
|
||||
log.Error("Cannot find needs for task %v: %v", t.ID, err)
|
||||
// Go on with empty needs.
|
||||
// If return error, the task will be wild, which means the runner will never get it when it has been assigned to the runner.
|
||||
// In contrast, missing needs is less serious.
|
||||
// And the task will fail and the runner will report the error in the logs.
|
||||
} else {
|
||||
task.Needs = needs
|
||||
}
|
||||
|
||||
return task, true, nil
|
||||
}
|
||||
|
||||
@@ -124,3 +135,46 @@ func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct {
|
||||
|
||||
return taskContext
|
||||
}
|
||||
|
||||
func findTaskNeeds(ctx context.Context, task *actions_model.ActionTask) (map[string]*runnerv1.TaskNeed, error) {
|
||||
if err := task.LoadAttributes(ctx); err != nil {
|
||||
return nil, fmt.Errorf("LoadAttributes: %w", err)
|
||||
}
|
||||
if len(task.Job.Needs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
needs := map[string]struct{}{}
|
||||
for _, v := range task.Job.Needs {
|
||||
needs[v] = struct{}{}
|
||||
}
|
||||
|
||||
jobs, _, err := actions_model.FindRunJobs(ctx, actions_model.FindRunJobOptions{RunID: task.Job.RunID})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FindRunJobs: %w", err)
|
||||
}
|
||||
|
||||
ret := make(map[string]*runnerv1.TaskNeed, len(needs))
|
||||
for _, job := range jobs {
|
||||
if _, ok := needs[job.JobID]; !ok {
|
||||
continue
|
||||
}
|
||||
if job.TaskID == 0 || !job.Status.IsDone() {
|
||||
// it shouldn't happen, or the job has been rerun
|
||||
continue
|
||||
}
|
||||
outputs := make(map[string]string)
|
||||
got, err := actions_model.FindTaskOutputByTaskID(ctx, job.TaskID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FindTaskOutputByTaskID: %w", err)
|
||||
}
|
||||
for _, v := range got {
|
||||
outputs[v.OutputKey] = v.OutputValue
|
||||
}
|
||||
ret[job.JobID] = &runnerv1.TaskNeed{
|
||||
Outputs: outputs,
|
||||
Result: runnerv1.Result(job.Status),
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
@@ -480,7 +480,7 @@ func ContainerRoutes(ctx gocontext.Context) *web.Route {
|
||||
)
|
||||
|
||||
// Manual mapping of routes because {image} can contain slashes which chi does not support
|
||||
r.Route("/*", "HEAD,GET,POST,PUT,PATCH,DELETE", func(ctx *context.Context) {
|
||||
r.RouteMethods("/*", "HEAD,GET,POST,PUT,PATCH,DELETE", func(ctx *context.Context) {
|
||||
path := ctx.Params("*")
|
||||
isHead := ctx.Req.Method == "HEAD"
|
||||
isGet := ctx.Req.Method == "GET"
|
||||
|
||||
@@ -142,7 +142,7 @@ func EditHook(ctx *context.APIContext) {
|
||||
|
||||
// DeleteHook delete a system hook
|
||||
func DeleteHook(ctx *context.APIContext) {
|
||||
// swagger:operation DELETE /amdin/hooks/{id} admin adminDeleteHook
|
||||
// swagger:operation DELETE /admin/hooks/{id} admin adminDeleteHook
|
||||
// ---
|
||||
// summary: Delete a hook
|
||||
// produces:
|
||||
|
||||
+10
-10
@@ -634,8 +634,8 @@ func mustEnableAttachments(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
// bind binding an obj to a func(ctx *context.APIContext)
|
||||
func bind[T any](obj T) http.HandlerFunc {
|
||||
return web.Wrap(func(ctx *context.APIContext) {
|
||||
func bind[T any](_ T) any {
|
||||
return func(ctx *context.APIContext) {
|
||||
theObj := new(T) // create a new form obj for every request but not use obj directly
|
||||
errs := binding.Bind(ctx.Req, theObj)
|
||||
if len(errs) > 0 {
|
||||
@@ -643,7 +643,7 @@ func bind[T any](obj T) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
web.SetForm(ctx, theObj)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// The OAuth2 plugin is expected to be executed first, as it must ignore the user id stored
|
||||
@@ -689,7 +689,7 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||
// Get user from session if logged in.
|
||||
m.Use(auth.APIAuth(group))
|
||||
|
||||
m.Use(context.ToggleAPI(&context.ToggleOptions{
|
||||
m.Use(auth.VerifyAuthWithOptionsAPI(&auth.VerifyOptions{
|
||||
SignInRequired: setting.Service.RequireSignInView,
|
||||
}))
|
||||
|
||||
@@ -1200,12 +1200,12 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||
m.Get("/{org}/permissions", reqToken(auth_model.AccessTokenScopeReadOrg), org.GetUserOrgsPermissions)
|
||||
}, context_service.UserAssignmentAPI())
|
||||
m.Post("/orgs", reqToken(auth_model.AccessTokenScopeWriteOrg), bind(api.CreateOrgOption{}), org.Create)
|
||||
m.Get("/orgs", reqToken(auth_model.AccessTokenScopeReadOrg), org.GetAll)
|
||||
m.Get("/orgs", org.GetAll)
|
||||
m.Group("/orgs/{org}", func() {
|
||||
m.Combo("").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.Get).
|
||||
m.Combo("").Get(org.Get).
|
||||
Patch(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.EditOrgOption{}), org.Edit).
|
||||
Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.Delete)
|
||||
m.Combo("/repos").Get(reqToken(auth_model.AccessTokenScopeReadOrg), user.ListOrgRepos).
|
||||
m.Combo("/repos").Get(user.ListOrgRepos).
|
||||
Post(reqToken(auth_model.AccessTokenScopeWriteOrg), bind(api.CreateRepoOption{}), repo.CreateOrgRepo)
|
||||
m.Group("/members", func() {
|
||||
m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListMembers)
|
||||
@@ -1213,8 +1213,8 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||
Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.DeleteMember)
|
||||
})
|
||||
m.Group("/public_members", func() {
|
||||
m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListPublicMembers)
|
||||
m.Combo("/{username}").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.IsPublicMember).
|
||||
m.Get("", org.ListPublicMembers)
|
||||
m.Combo("/{username}").Get(org.IsPublicMember).
|
||||
Put(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgMembership(), org.PublicizeMember).
|
||||
Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgMembership(), org.ConcealMember)
|
||||
})
|
||||
@@ -1224,7 +1224,7 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||
m.Get("/search", reqToken(auth_model.AccessTokenScopeReadOrg), org.SearchTeam)
|
||||
}, reqOrgMembership())
|
||||
m.Group("/labels", func() {
|
||||
m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListLabels)
|
||||
m.Get("", org.ListLabels)
|
||||
m.Post("", reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.CreateLabelOption{}), org.CreateLabel)
|
||||
m.Combo("/{id}").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.GetLabel).
|
||||
Patch(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.EditLabelOption{}), org.EditLabel).
|
||||
|
||||
@@ -173,7 +173,7 @@ func ListIssueCommentsAndTimeline(ctx *context.APIContext) {
|
||||
IssueID: issue.ID,
|
||||
Since: since,
|
||||
Before: before,
|
||||
Type: issues_model.CommentTypeUnknown,
|
||||
Type: issues_model.CommentTypeUndefined,
|
||||
}
|
||||
|
||||
comments, err := issues_model.FindComments(ctx, opts)
|
||||
@@ -549,7 +549,7 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption)
|
||||
return
|
||||
}
|
||||
|
||||
if comment.Type != issues_model.CommentTypeComment && comment.Type != issues_model.CommentTypeReview && comment.Type != issues_model.CommentTypeCode {
|
||||
if !comment.Type.HasContentSupport() {
|
||||
ctx.Status(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
+19
-21
@@ -58,10 +58,10 @@ func NewWikiPage(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
wikiName := wiki_service.NormalizeWikiName(form.Title)
|
||||
wikiName := wiki_service.UserTitleToWebPath("", form.Title)
|
||||
|
||||
if len(form.Message) == 0 {
|
||||
form.Message = fmt.Sprintf("Add '%s'", form.Title)
|
||||
form.Message = fmt.Sprintf("Add %q", form.Title)
|
||||
}
|
||||
|
||||
content, err := base64.StdEncoding.DecodeString(form.ContentBase64)
|
||||
@@ -85,7 +85,7 @@ func NewWikiPage(ctx *context.APIContext) {
|
||||
wikiPage := getWikiPage(ctx, wikiName)
|
||||
|
||||
if !ctx.Written() {
|
||||
notification.NotifyNewWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName, form.Message)
|
||||
notification.NotifyNewWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, string(wikiName), form.Message)
|
||||
ctx.JSON(http.StatusCreated, wikiPage)
|
||||
}
|
||||
}
|
||||
@@ -127,15 +127,15 @@ func EditWikiPage(ctx *context.APIContext) {
|
||||
|
||||
form := web.GetForm(ctx).(*api.CreateWikiPageOptions)
|
||||
|
||||
oldWikiName := wiki_service.NormalizeWikiName(ctx.Params(":pageName"))
|
||||
newWikiName := wiki_service.NormalizeWikiName(form.Title)
|
||||
oldWikiName := wiki_service.WebPathFromRequest(ctx.Params(":pageName"))
|
||||
newWikiName := wiki_service.UserTitleToWebPath("", form.Title)
|
||||
|
||||
if len(newWikiName) == 0 {
|
||||
newWikiName = oldWikiName
|
||||
}
|
||||
|
||||
if len(form.Message) == 0 {
|
||||
form.Message = fmt.Sprintf("Update '%s'", newWikiName)
|
||||
form.Message = fmt.Sprintf("Update %q", newWikiName)
|
||||
}
|
||||
|
||||
content, err := base64.StdEncoding.DecodeString(form.ContentBase64)
|
||||
@@ -153,14 +153,12 @@ func EditWikiPage(ctx *context.APIContext) {
|
||||
wikiPage := getWikiPage(ctx, newWikiName)
|
||||
|
||||
if !ctx.Written() {
|
||||
notification.NotifyEditWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, newWikiName, form.Message)
|
||||
notification.NotifyEditWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, string(newWikiName), form.Message)
|
||||
ctx.JSON(http.StatusOK, wikiPage)
|
||||
}
|
||||
}
|
||||
|
||||
func getWikiPage(ctx *context.APIContext, title string) *api.WikiPage {
|
||||
title = wiki_service.NormalizeWikiName(title)
|
||||
|
||||
func getWikiPage(ctx *context.APIContext, wikiName wiki_service.WebPath) *api.WikiPage {
|
||||
wikiRepo, commit := findWikiRepoCommit(ctx)
|
||||
if wikiRepo != nil {
|
||||
defer wikiRepo.Close()
|
||||
@@ -170,7 +168,7 @@ func getWikiPage(ctx *context.APIContext, title string) *api.WikiPage {
|
||||
}
|
||||
|
||||
// lookup filename in wiki - get filecontent, real filename
|
||||
content, pageFilename := wikiContentsByName(ctx, commit, title, false)
|
||||
content, pageFilename := wikiContentsByName(ctx, commit, wikiName, false)
|
||||
if ctx.Written() {
|
||||
return nil
|
||||
}
|
||||
@@ -196,7 +194,7 @@ func getWikiPage(ctx *context.APIContext, title string) *api.WikiPage {
|
||||
}
|
||||
|
||||
return &api.WikiPage{
|
||||
WikiPageMetaData: convert.ToWikiPageMetaData(title, lastCommit, ctx.Repo.Repository),
|
||||
WikiPageMetaData: convert.ToWikiPageMetaData(wikiName, lastCommit, ctx.Repo.Repository),
|
||||
ContentBase64: content,
|
||||
CommitCount: commitsCount,
|
||||
Sidebar: sidebarContent,
|
||||
@@ -233,7 +231,7 @@ func DeleteWikiPage(ctx *context.APIContext) {
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
|
||||
wikiName := wiki_service.NormalizeWikiName(ctx.Params(":pageName"))
|
||||
wikiName := wiki_service.WebPathFromRequest(ctx.Params(":pageName"))
|
||||
|
||||
if err := wiki_service.DeleteWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName); err != nil {
|
||||
if err.Error() == "file does not exist" {
|
||||
@@ -244,7 +242,7 @@ func DeleteWikiPage(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
notification.NotifyDeleteWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName)
|
||||
notification.NotifyDeleteWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, string(wikiName))
|
||||
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
@@ -316,7 +314,7 @@ func ListWikiPages(ctx *context.APIContext) {
|
||||
ctx.Error(http.StatusInternalServerError, "GetCommit", err)
|
||||
return
|
||||
}
|
||||
wikiName, err := wiki_service.FilenameToName(entry.Name())
|
||||
wikiName, err := wiki_service.GitPathToWebPath(entry.Name())
|
||||
if err != nil {
|
||||
if repo_model.IsErrWikiInvalidFileName(err) {
|
||||
continue
|
||||
@@ -361,7 +359,7 @@ func GetWikiPage(ctx *context.APIContext) {
|
||||
// "$ref": "#/responses/notFound"
|
||||
|
||||
// get requested pagename
|
||||
pageName := wiki_service.NormalizeWikiName(ctx.Params(":pageName"))
|
||||
pageName := wiki_service.WebPathFromRequest(ctx.Params(":pageName"))
|
||||
|
||||
wikiPage := getWikiPage(ctx, pageName)
|
||||
if !ctx.Written() {
|
||||
@@ -411,7 +409,7 @@ func ListPageRevisions(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
// get requested pagename
|
||||
pageName := wiki_service.NormalizeWikiName(ctx.Params(":pageName"))
|
||||
pageName := wiki_service.WebPathFromRequest(ctx.Params(":pageName"))
|
||||
if len(pageName) == 0 {
|
||||
pageName = "Home"
|
||||
}
|
||||
@@ -502,9 +500,9 @@ func wikiContentsByEntry(ctx *context.APIContext, entry *git.TreeEntry) string {
|
||||
|
||||
// wikiContentsByName returns the contents of a wiki page, along with a boolean
|
||||
// indicating whether the page exists. Writes to ctx if an error occurs.
|
||||
func wikiContentsByName(ctx *context.APIContext, commit *git.Commit, wikiName string, isSidebarOrFooter bool) (string, string) {
|
||||
pageFilename := wiki_service.NameToFilename(wikiName)
|
||||
entry, err := findEntryForFile(commit, pageFilename)
|
||||
func wikiContentsByName(ctx *context.APIContext, commit *git.Commit, wikiName wiki_service.WebPath, isSidebarOrFooter bool) (string, string) {
|
||||
gitFilename := wiki_service.WebPathToGitPath(wikiName)
|
||||
entry, err := findEntryForFile(commit, gitFilename)
|
||||
if err != nil {
|
||||
if git.IsErrNotExist(err) {
|
||||
if !isSidebarOrFooter {
|
||||
@@ -515,5 +513,5 @@ func wikiContentsByName(ctx *context.APIContext, commit *git.Commit, wikiName st
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
return wikiContentsByEntry(ctx, entry), pageFilename
|
||||
return wikiContentsByEntry(ctx, entry), gitFilename
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user