Merge remote-tracking branch 'upstream/main' into limit-repo-size

This commit is contained in:
DmitryFrolovTri
2023-05-03 14:40:58 +00:00
477 changed files with 7190 additions and 5990 deletions
+27 -1
View File
@@ -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
}
+54
View File
@@ -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
}
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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
View File
@@ -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).
+2 -2
View File
@@ -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
View File
@@ -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
}