From 56a0a9c750b4cd48ca44a22ff0c860b9d035c950 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 24 Feb 2025 10:11:29 +0800 Subject: [PATCH 1/6] Fix git empty check and HEAD request (#33690) --- routers/web/repo/githttp.go | 2 +- services/context/api.go | 5 ++++ tests/integration/empty_repo_test.go | 8 +++++ tests/integration/git_smart_http_test.go | 37 ++++++++++++++---------- 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go index e27040edc6..5b7b0188dc 100644 --- a/routers/web/repo/githttp.go +++ b/routers/web/repo/githttp.go @@ -78,7 +78,7 @@ func httpBase(ctx *context.Context) *serviceHandler { strings.HasSuffix(ctx.Req.URL.Path, "git-upload-archive") { isPull = true } else { - isPull = ctx.Req.Method == "GET" + isPull = ctx.Req.Method == "HEAD" || ctx.Req.Method == "GET" } var accessMode perm.AccessMode diff --git a/services/context/api.go b/services/context/api.go index 230c3456d1..c163de036c 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -291,6 +291,11 @@ func RepoRefForAPI(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ctx := GetAPIContext(req) + if ctx.Repo.Repository.IsEmpty { + ctx.APIErrorNotFound("repository is empty") + return + } + if ctx.Repo.GitRepo == nil { ctx.APIErrorInternal(fmt.Errorf("no open git repo")) return diff --git a/tests/integration/empty_repo_test.go b/tests/integration/empty_repo_test.go index b19774a826..e122531dc9 100644 --- a/tests/integration/empty_repo_test.go +++ b/tests/integration/empty_repo_test.go @@ -60,12 +60,20 @@ func TestEmptyRepoAddFile(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user30") + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository) + + // test web page req := NewRequest(t, "GET", "/user30/empty") resp := session.MakeRequest(t, req, http.StatusOK) bodyString := resp.Body.String() assert.Contains(t, bodyString, "empty-repo-guide") assert.True(t, test.IsNormalPageCompleted(bodyString)) + // test api + req = NewRequest(t, "GET", "/api/v1/repos/user30/empty/raw/main/README.md").AddTokenAuth(token) + session.MakeRequest(t, req, http.StatusNotFound) + + // create a new file req = NewRequest(t, "GET", "/user30/empty/_new/"+setting.Repository.DefaultBranch) resp = session.MakeRequest(t, req, http.StatusOK) doc := NewHTMLParser(t, resp.Body).Find(`input[name="commit_choice"]`) diff --git a/tests/integration/git_smart_http_test.go b/tests/integration/git_smart_http_test.go index 15336b9b81..55d647672a 100644 --- a/tests/integration/git_smart_http_test.go +++ b/tests/integration/git_smart_http_test.go @@ -9,7 +9,10 @@ import ( "net/url" "testing" + "code.gitea.io/gitea/modules/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestGitSmartHTTP(t *testing.T) { @@ -18,51 +21,55 @@ func TestGitSmartHTTP(t *testing.T) { func testGitSmartHTTP(t *testing.T, u *url.URL) { kases := []struct { - p string - code int + method, path string + code int }{ { - p: "user2/repo1/info/refs", + path: "user2/repo1/info/refs", code: http.StatusOK, }, { - p: "user2/repo1/HEAD", + method: "HEAD", + path: "user2/repo1/info/refs", + code: http.StatusOK, + }, + { + path: "user2/repo1/HEAD", code: http.StatusOK, }, { - p: "user2/repo1/objects/info/alternates", + path: "user2/repo1/objects/info/alternates", code: http.StatusNotFound, }, { - p: "user2/repo1/objects/info/http-alternates", + path: "user2/repo1/objects/info/http-alternates", code: http.StatusNotFound, }, { - p: "user2/repo1/../../custom/conf/app.ini", + path: "user2/repo1/../../custom/conf/app.ini", code: http.StatusNotFound, }, { - p: "user2/repo1/objects/info/../../../../custom/conf/app.ini", + path: "user2/repo1/objects/info/../../../../custom/conf/app.ini", code: http.StatusNotFound, }, { - p: `user2/repo1/objects/info/..\..\..\..\custom\conf\app.ini`, + path: `user2/repo1/objects/info/..\..\..\..\custom\conf\app.ini`, code: http.StatusBadRequest, }, } for _, kase := range kases { - t.Run(kase.p, func(t *testing.T) { - p := u.String() + kase.p - req, err := http.NewRequest("GET", p, nil) - assert.NoError(t, err) + t.Run(kase.path, func(t *testing.T) { + req, err := http.NewRequest(util.IfZero(kase.method, "GET"), u.String()+kase.path, nil) + require.NoError(t, err) req.SetBasicAuth("user2", userPassword) resp, err := http.DefaultClient.Do(req) - assert.NoError(t, err) + require.NoError(t, err) defer resp.Body.Close() assert.EqualValues(t, kase.code, resp.StatusCode) _, err = io.ReadAll(resp.Body) - assert.NoError(t, err) + require.NoError(t, err) }) } } From adf7018bfddfd7fd817b2212021eba7210cc3cb0 Mon Sep 17 00:00:00 2001 From: Arif Er <46054733+arifer612@users.noreply.github.com> Date: Mon, 24 Feb 2025 14:37:37 +0800 Subject: [PATCH 2/6] Fix OCI image.version annotation for releases to use full semver (#33698) This commit fixes the docker build workflow such that semver-tagged releases use the full semver for the OCI `org.opencontainers.image.version` annotation, instead of using the major version only. This is done by changing the order of the tags that the `docker/metadata-action` action is told to generate. Since the tags that the action is told to generate are all of the same priority, the first in the list will be used to set the annotation. There is no need to fix the other two docker build workflows, i.e., (i) the nightly releases and (ii) the rc-tagged releases. This is because (i) the nightly releases do not get tagged with a semver, so the issue does not exist, and (ii) rc-tagged releases only get built with one tag, so the issue of needing to set an order of how tags are generated is irrelevant. Resolves go-gitea/gitea#33697. --- .github/workflows/release-tag-version.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-tag-version.yml b/.github/workflows/release-tag-version.yml index f67b76f408..08bb9baecf 100644 --- a/.github/workflows/release-tag-version.yml +++ b/.github/workflows/release-tag-version.yml @@ -88,9 +88,9 @@ jobs: # 1.2 # 1.2.3 tags: | + type=semver,pattern={{version}} type=semver,pattern={{major}} type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{version}} - name: Login to Docker Hub uses: docker/login-action@v3 with: @@ -126,9 +126,9 @@ jobs: # 1.2 # 1.2.3 tags: | + type=semver,pattern={{version}} type=semver,pattern={{major}} type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{version}} - name: Login to Docker Hub uses: docker/login-action@v3 with: From 555d64d024a69f249b42ff354e06226b5ff7c746 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 24 Feb 2025 16:40:46 +0800 Subject: [PATCH 3/6] Always show the "rerun" button for action jobs (#33692) And improve the mock code. --- routers/web/devtest/mock_actions.go | 38 ++++++++++++++++++++++-- routers/web/web.go | 1 + templates/devtest/repo-action-view.tmpl | 9 ++++-- web_src/js/components/RepoActionView.vue | 12 ++------ 4 files changed, 46 insertions(+), 14 deletions(-) diff --git a/routers/web/devtest/mock_actions.go b/routers/web/devtest/mock_actions.go index e6539bb31f..3ce75dfad2 100644 --- a/routers/web/devtest/mock_actions.go +++ b/routers/web/devtest/mock_actions.go @@ -52,13 +52,22 @@ func generateMockStepsLog(logCur actions.LogCursor) (stepsLog []*actions.ViewSte return stepsLog } -func MockActionsRunsJobs(ctx *context.Context) { - req := web.GetForm(ctx).(*actions.ViewRequest) +func MockActionsView(ctx *context.Context) { + ctx.Data["RunID"] = ctx.PathParam("run") + ctx.Data["JobID"] = ctx.PathParam("job") + ctx.HTML(http.StatusOK, "devtest/repo-action-view") +} +func MockActionsRunsJobs(ctx *context.Context) { + runID := ctx.PathParamInt64("run") + + req := web.GetForm(ctx).(*actions.ViewRequest) resp := &actions.ViewResponse{} resp.State.Run.TitleHTML = `mock run title link` resp.State.Run.Status = actions_model.StatusRunning.String() - resp.State.Run.CanCancel = true + resp.State.Run.CanCancel = runID == 10 + resp.State.Run.CanApprove = runID == 20 + resp.State.Run.CanRerun = runID == 30 resp.State.Run.CanDeleteArtifact = true resp.State.Run.WorkflowID = "workflow-id" resp.State.Run.WorkflowLink = "./workflow-link" @@ -85,6 +94,29 @@ func MockActionsRunsJobs(ctx *context.Context) { Size: 1024 * 1024, Status: "completed", }) + + resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{ + ID: runID * 10, + Name: "job 100", + Status: actions_model.StatusRunning.String(), + CanRerun: true, + Duration: "1h", + }) + resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{ + ID: runID*10 + 1, + Name: "job 101", + Status: actions_model.StatusWaiting.String(), + CanRerun: false, + Duration: "2h", + }) + resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{ + ID: runID*10 + 2, + Name: "job 102", + Status: actions_model.StatusFailure.String(), + CanRerun: false, + Duration: "3h", + }) + resp.State.CurrentJob.Steps = append(resp.State.CurrentJob.Steps, &actions.ViewJobStep{ Summary: "step 0 (mock slow)", Duration: time.Hour.String(), diff --git a/routers/web/web.go b/routers/web/web.go index a5175e8830..01dc8cf697 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1634,6 +1634,7 @@ func registerRoutes(m *web.Router) { m.Any("", devtest.List) m.Any("/fetch-action-test", devtest.FetchActionTest) m.Any("/{sub}", devtest.Tmpl) + m.Get("/repo-action-view/{run}/{job}", devtest.MockActionsView) m.Post("/actions-mock/runs/{run}/jobs/{job}", web.Bind(actions.ViewRequest{}), devtest.MockActionsRunsJobs) }) } diff --git a/templates/devtest/repo-action-view.tmpl b/templates/devtest/repo-action-view.tmpl index 9c6bdf13da..677eccc062 100644 --- a/templates/devtest/repo-action-view.tmpl +++ b/templates/devtest/repo-action-view.tmpl @@ -1,8 +1,13 @@ {{template "base/head" .}}
+ {{template "repo/actions/view_component" (dict - "RunIndex" 1 - "JobIndex" 2 + "RunIndex" (or .RunID 10) + "JobIndex" (or .JobID 100) "ActionsURL" (print AppSubUrl "/devtest/actions-mock") )}}
diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 03c8464060..2ef528620d 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -105,7 +105,6 @@ export default defineComponent({ intervalID: null as IntervalId | null, currentJobStepsStates: [] as Array>, artifacts: [] as Array>, - onHoverRerunIndex: -1, menuVisible: false, isFullScreen: false, timeVisible: { @@ -120,7 +119,7 @@ export default defineComponent({ link: '', title: '', titleHTML: '', - status: 'unknown' as RunStatus, + status: '' as RunStatus, // do not show the status before initialized, otherwise it would show an incorrect "error" icon canCancel: false, canApprove: false, canRerun: false, @@ -492,13 +491,13 @@ export default defineComponent({
- +
{{ job.name }}
- + {{ job.duration }}
@@ -721,11 +720,6 @@ export default defineComponent({ .job-brief-item .job-brief-rerun { cursor: pointer; - transition: transform 0.2s; -} - -.job-brief-item .job-brief-rerun:hover { - transform: scale(130%); } .job-brief-item .job-brief-item-left { From 2cd2ae07a7ff267eaa9d2b984d015c58edcb0647 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Tue, 25 Feb 2025 02:24:56 +0800 Subject: [PATCH 4/6] Add No Results Prompt Message on Issue List Page (#33699) --- options/locale/locale_en-US.ini | 2 ++ templates/shared/issuelist.tmpl | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index c2c5b07b65..4c25ba3205 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1465,6 +1465,8 @@ issues.filter_milestones = Filter Milestone issues.filter_projects = Filter Project issues.filter_labels = Filter Label issues.filter_reviewers = Filter Reviewer +issues.filter_no_results = No results +issues.filter_no_results_placeholder = Try adjusting your search filters. issues.new = New Issue issues.new.title_empty = Title cannot be empty issues.new.labels = Labels diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl index fe7f2fd8bf..30670c3b0f 100644 --- a/templates/shared/issuelist.tmpl +++ b/templates/shared/issuelist.tmpl @@ -153,6 +153,11 @@
{{end}}
+ {{else}} +
+

{{ctx.Locale.Tr "repo.issues.filter_no_results"}}

+

{{ctx.Locale.Tr "repo.issues.filter_no_results_placeholder"}}

+
{{end}} {{if .IssueIndexerUnavailable}}
From 76b7f95a276a6db564f29c9b11c94b5ce7f09cb8 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 24 Feb 2025 11:29:32 -0800 Subject: [PATCH 5/6] Optimize user dashboard loading (#33686) Fix #33582 Fix #31698 When a user login, the dashboard should load all feed belongs to him with no any conditions. The complicated conditions should be applied only for another user view this user's profile. --- models/activities/action.go | 30 +++++++++++++++++++----------- models/activities/action_list.go | 28 +++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/models/activities/action.go b/models/activities/action.go index adc442b88b..52dffe07fd 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -454,6 +454,24 @@ func ActivityReadable(user, doer *user_model.User) bool { doer != nil && (doer.IsAdmin || user.ID == doer.ID) } +func FeedDateCond(opts GetFeedsOptions) builder.Cond { + cond := builder.NewCond() + if opts.Date == "" { + return cond + } + + dateLow, err := time.ParseInLocation("2006-01-02", opts.Date, setting.DefaultUILocation) + if err != nil { + log.Warn("Unable to parse %s, filter not applied: %v", opts.Date, err) + } else { + dateHigh := dateLow.Add(86399000000000) // 23h59m59s + + cond = cond.And(builder.Gte{"`action`.created_unix": dateLow.Unix()}) + cond = cond.And(builder.Lte{"`action`.created_unix": dateHigh.Unix()}) + } + return cond +} + func ActivityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.Cond, error) { cond := builder.NewCond() @@ -534,17 +552,7 @@ func ActivityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder. cond = cond.And(builder.Eq{"is_deleted": false}) } - if opts.Date != "" { - dateLow, err := time.ParseInLocation("2006-01-02", opts.Date, setting.DefaultUILocation) - if err != nil { - log.Warn("Unable to parse %s, filter not applied: %v", opts.Date, err) - } else { - dateHigh := dateLow.Add(86399000000000) // 23h59m59s - - cond = cond.And(builder.Gte{"`action`.created_unix": dateLow.Unix()}) - cond = cond.And(builder.Lte{"`action`.created_unix": dateHigh.Unix()}) - } - } + cond = cond.And(FeedDateCond(opts)) return cond, nil } diff --git a/models/activities/action_list.go b/models/activities/action_list.go index 5f9acb8f2a..f7ea48f03e 100644 --- a/models/activities/action_list.go +++ b/models/activities/action_list.go @@ -208,9 +208,31 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo") } - cond, err := ActivityQueryCondition(ctx, opts) - if err != nil { - return nil, 0, err + var err error + var cond builder.Cond + // if the actor is the requested user or is an administrator, we can skip the ActivityQueryCondition + if opts.Actor != nil && opts.RequestedUser != nil && (opts.Actor.IsAdmin || opts.Actor.ID == opts.RequestedUser.ID) { + cond = builder.Eq{ + "user_id": opts.RequestedUser.ID, + }.And( + FeedDateCond(opts), + ) + + if !opts.IncludeDeleted { + cond = cond.And(builder.Eq{"is_deleted": false}) + } + + if !opts.IncludePrivate { + cond = cond.And(builder.Eq{"is_private": false}) + } + if opts.OnlyPerformedBy { + cond = cond.And(builder.Eq{"act_user_id": opts.RequestedUser.ID}) + } + } else { + cond, err = ActivityQueryCondition(ctx, opts) + if err != nil { + return nil, 0, err + } } actions := make([]*Action, 0, opts.PageSize) From 7535af20da36bdcf4d13007ea780ed0541c66c0b Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Mon, 24 Feb 2025 15:15:18 -0500 Subject: [PATCH 6/6] bump x/crypto & x/oauth2 (#33704) --- go.mod | 4 ++-- go.sum | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index ca5d47aff4..f2213b584e 100644 --- a/go.mod +++ b/go.mod @@ -117,10 +117,10 @@ require ( github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc github.com/yuin/goldmark-meta v1.1.0 gitlab.com/gitlab-org/api/client-go v0.123.0 - golang.org/x/crypto v0.33.0 + golang.org/x/crypto v0.35.0 golang.org/x/image v0.24.0 golang.org/x/net v0.35.0 - golang.org/x/oauth2 v0.26.0 + golang.org/x/oauth2 v0.27.0 golang.org/x/sync v0.11.0 golang.org/x/sys v0.30.0 golang.org/x/text v0.22.0 diff --git a/go.sum b/go.sum index f2bae16405..4047c846e4 100644 --- a/go.sum +++ b/go.sum @@ -831,8 +831,9 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= +golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4= golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ= @@ -868,8 +869,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= -golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= +golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=