|
| 1 | +// Copyright 2025 The Gitea Authors. All rights reserved. |
| 2 | +// SPDX-License-Identifier: MIT |
| 3 | + |
| 4 | +package integration |
| 5 | + |
| 6 | +import ( |
| 7 | + "fmt" |
| 8 | + "net/http" |
| 9 | + "net/url" |
| 10 | + "strings" |
| 11 | + "testing" |
| 12 | + "time" |
| 13 | + |
| 14 | + auth_model "code.gitea.io/gitea/models/auth" |
| 15 | + repo_model "code.gitea.io/gitea/models/repo" |
| 16 | + "code.gitea.io/gitea/models/unittest" |
| 17 | + user_model "code.gitea.io/gitea/models/user" |
| 18 | + api "code.gitea.io/gitea/modules/structs" |
| 19 | + "code.gitea.io/gitea/modules/util" |
| 20 | + |
| 21 | + "github.com/stretchr/testify/assert" |
| 22 | + "github.com/stretchr/testify/require" |
| 23 | +) |
| 24 | + |
| 25 | +func TestRepoMergeUpstream(t *testing.T) { |
| 26 | + onGiteaRun(t, func(*testing.T, *url.URL) { |
| 27 | + forkUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) |
| 28 | + |
| 29 | + baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) |
| 30 | + baseUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: baseRepo.OwnerID}) |
| 31 | + |
| 32 | + checkFileContent := func(exp string) { |
| 33 | + req := NewRequest(t, "GET", fmt.Sprintf("/%s/test-repo-fork/raw/branch/master/new-file.txt", forkUser.Name)) |
| 34 | + resp := MakeRequest(t, req, http.StatusOK) |
| 35 | + require.Equal(t, exp, resp.Body.String()) |
| 36 | + } |
| 37 | + |
| 38 | + session := loginUser(t, forkUser.Name) |
| 39 | + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) |
| 40 | + |
| 41 | + // create a fork |
| 42 | + req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/forks", baseUser.Name, baseRepo.Name), &api.CreateForkOption{ |
| 43 | + Name: util.ToPointer("test-repo-fork"), |
| 44 | + }).AddTokenAuth(token) |
| 45 | + MakeRequest(t, req, http.StatusAccepted) |
| 46 | + forkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: forkUser.ID, Name: "test-repo-fork"}) |
| 47 | + |
| 48 | + // add a file in base repo |
| 49 | + require.NoError(t, createOrReplaceFileInBranch(baseUser, baseRepo, "new-file.txt", "master", "test-content-1")) |
| 50 | + |
| 51 | + // the repo shows a prompt to "sync fork" |
| 52 | + var mergeUpstreamLink string |
| 53 | + require.Eventually(t, func() bool { |
| 54 | + resp := session.MakeRequest(t, NewRequestf(t, "GET", "/%s/test-repo-fork", forkUser.Name), http.StatusOK) |
| 55 | + htmlDoc := NewHTMLParser(t, resp.Body) |
| 56 | + respMsg, _ := htmlDoc.Find(".ui.message").Html() |
| 57 | + if !strings.Contains(respMsg, `This branch is 1 commit behind <a href="/user2/repo1/src/branch/master">user2/repo1:master</a>`) { |
| 58 | + return false |
| 59 | + } |
| 60 | + mergeUpstreamLink = htmlDoc.Find("button[data-url*='merge-upstream']").AttrOr("data-url", "") |
| 61 | + require.NotEmpty(t, mergeUpstreamLink) |
| 62 | + return true |
| 63 | + }, 5*time.Second, 100*time.Millisecond) |
| 64 | + |
| 65 | + // click the "sync fork" button |
| 66 | + req = NewRequestWithValues(t, "POST", mergeUpstreamLink, map[string]string{"_csrf": GetUserCSRFToken(t, session)}) |
| 67 | + session.MakeRequest(t, req, http.StatusOK) |
| 68 | + checkFileContent("test-content-1") |
| 69 | + |
| 70 | + // update the files |
| 71 | + require.NoError(t, createOrReplaceFileInBranch(forkUser, forkRepo, "new-file-other.txt", "master", "test-content-other")) |
| 72 | + require.NoError(t, createOrReplaceFileInBranch(baseUser, baseRepo, "new-file.txt", "master", "test-content-2")) |
| 73 | + require.Eventually(t, func() bool { |
| 74 | + resp := session.MakeRequest(t, NewRequestf(t, "GET", "/%s/test-repo-fork", forkUser.Name), http.StatusOK) |
| 75 | + htmlDoc := NewHTMLParser(t, resp.Body) |
| 76 | + respMsg, _ := htmlDoc.Find(".ui.message:not(.positive)").Html() |
| 77 | + return strings.Contains(respMsg, `The base branch <a href="/user2/repo1/src/branch/master">user2/repo1:master</a> has new changes`) |
| 78 | + }, 5*time.Second, 100*time.Millisecond) |
| 79 | + |
| 80 | + // and do the merge-upstream by API |
| 81 | + req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/test-repo-fork/merge-upstream", forkUser.Name), &api.MergeUpstreamRequest{ |
| 82 | + Branch: "master", |
| 83 | + }).AddTokenAuth(token) |
| 84 | + resp := MakeRequest(t, req, http.StatusOK) |
| 85 | + checkFileContent("test-content-2") |
| 86 | + |
| 87 | + var mergeResp api.MergeUpstreamResponse |
| 88 | + DecodeJSON(t, resp, &mergeResp) |
| 89 | + assert.Equal(t, "merge", mergeResp.MergeStyle) |
| 90 | + }) |
| 91 | +} |
0 commit comments