Allow instance-wide disabling of forking
For small, personal self-hosted instances with no user signups, the fork button is just a noise. This patch allows disabling them like stars can be disabled too. Disabling forks does not only remove the buttons from the web UI, it also disables the routes that could be used to create forks. Fixes #2441. Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu>
This commit is contained in:
		
					parent
					
						
							
								b7ea2ea463
							
						
					
				
			
			
				commit
				
					
						0ea021c8c9
					
				
			
		
					 14 changed files with 162 additions and 60 deletions
				
			
		| 
						 | 
				
			
			@ -991,6 +991,9 @@ LEVEL = Info
 | 
			
		|||
;; Disable stars feature.
 | 
			
		||||
;DISABLE_STARS = false
 | 
			
		||||
;;
 | 
			
		||||
;; Disable repository forking.
 | 
			
		||||
;DISABLE_FORKS = false
 | 
			
		||||
;;
 | 
			
		||||
;; The default branch name of new repositories
 | 
			
		||||
;DEFAULT_BRANCH = main
 | 
			
		||||
;;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -198,6 +198,7 @@ func Contexter() func(next http.Handler) http.Handler {
 | 
			
		|||
			// FIXME: do we really always need these setting? There should be someway to have to avoid having to always set these
 | 
			
		||||
			ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
 | 
			
		||||
			ctx.Data["DisableStars"] = setting.Repository.DisableStars
 | 
			
		||||
			ctx.Data["DisableForks"] = setting.Repository.DisableForks
 | 
			
		||||
			ctx.Data["EnableActions"] = setting.Actions.Enabled
 | 
			
		||||
 | 
			
		||||
			ctx.Data["ManifestData"] = setting.ManifestData
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,6 +50,7 @@ var (
 | 
			
		|||
		PrefixArchiveFiles                      bool
 | 
			
		||||
		DisableMigrations                       bool
 | 
			
		||||
		DisableStars                            bool `ini:"DISABLE_STARS"`
 | 
			
		||||
		DisableForks                            bool
 | 
			
		||||
		DefaultBranch                           string
 | 
			
		||||
		AllowAdoptionOfUnadoptedRepositories    bool
 | 
			
		||||
		AllowDeleteOfUnadoptedRepositories      bool
 | 
			
		||||
| 
						 | 
				
			
			@ -172,6 +173,7 @@ var (
 | 
			
		|||
		PrefixArchiveFiles:                      true,
 | 
			
		||||
		DisableMigrations:                       false,
 | 
			
		||||
		DisableStars:                            false,
 | 
			
		||||
		DisableForks:                            false,
 | 
			
		||||
		DefaultBranch:                           "main",
 | 
			
		||||
		AllowForkWithoutMaximumLimit:            true,
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ type GeneralRepoSettings struct {
 | 
			
		|||
	HTTPGitDisabled      bool `json:"http_git_disabled"`
 | 
			
		||||
	MigrationsDisabled   bool `json:"migrations_disabled"`
 | 
			
		||||
	StarsDisabled        bool `json:"stars_disabled"`
 | 
			
		||||
	ForksDisabled        bool `json:"forks_disabled"`
 | 
			
		||||
	TimeTrackingDisabled bool `json:"time_tracking_disabled"`
 | 
			
		||||
	LFSDisabled          bool `json:"lfs_disabled"`
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1161,8 +1161,10 @@ func Routes() *web.Route {
 | 
			
		|||
				m.Get("/raw/*", context.ReferencesGitRepo(), context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetRawFile)
 | 
			
		||||
				m.Get("/media/*", context.ReferencesGitRepo(), context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetRawFileOrLFS)
 | 
			
		||||
				m.Get("/archive/*", reqRepoReader(unit.TypeCode), repo.GetArchive)
 | 
			
		||||
				m.Combo("/forks").Get(repo.ListForks).
 | 
			
		||||
					Post(reqToken(), reqRepoReader(unit.TypeCode), bind(api.CreateForkOption{}), repo.CreateFork)
 | 
			
		||||
				if !setting.Repository.DisableForks {
 | 
			
		||||
					m.Combo("/forks").Get(repo.ListForks).
 | 
			
		||||
						Post(reqToken(), reqRepoReader(unit.TypeCode), bind(api.CreateForkOption{}), repo.CreateFork)
 | 
			
		||||
				}
 | 
			
		||||
				m.Group("/branches", func() {
 | 
			
		||||
					m.Get("", repo.ListBranches)
 | 
			
		||||
					m.Get("/*", repo.GetBranch)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,6 +61,7 @@ func GetGeneralRepoSettings(ctx *context.APIContext) {
 | 
			
		|||
		HTTPGitDisabled:      setting.Repository.DisableHTTPGit,
 | 
			
		||||
		MigrationsDisabled:   setting.Repository.DisableMigrations,
 | 
			
		||||
		StarsDisabled:        setting.Repository.DisableStars,
 | 
			
		||||
		ForksDisabled:        setting.Repository.DisableForks,
 | 
			
		||||
		TimeTrackingDisabled: !setting.Service.EnableTimetracking,
 | 
			
		||||
		LFSDisabled:          !setting.LFS.StartServer,
 | 
			
		||||
	})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -968,7 +968,9 @@ func registerRoutes(m *web.Route) {
 | 
			
		|||
		m.Post("/create", web.Bind(forms.CreateRepoForm{}), repo.CreatePost)
 | 
			
		||||
		m.Get("/migrate", repo.Migrate)
 | 
			
		||||
		m.Post("/migrate", web.Bind(forms.MigrateRepoForm{}), repo.MigratePost)
 | 
			
		||||
		m.Get("/fork/{repoid}", context.RepoIDAssignment(), context.UnitTypes(), reqRepoCodeReader, repo.ForkByID)
 | 
			
		||||
		if !setting.Repository.DisableForks {
 | 
			
		||||
			m.Get("/fork/{repoid}", context.RepoIDAssignment(), context.UnitTypes(), reqRepoCodeReader, repo.ForkByID)
 | 
			
		||||
		}
 | 
			
		||||
		m.Get("/search", repo.SearchRepo)
 | 
			
		||||
	}, reqSignIn)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1148,8 +1150,10 @@ func registerRoutes(m *web.Route) {
 | 
			
		|||
 | 
			
		||||
	// Grouping for those endpoints that do require authentication
 | 
			
		||||
	m.Group("/{username}/{reponame}", func() {
 | 
			
		||||
		m.Combo("/fork", reqRepoCodeReader).Get(repo.Fork).
 | 
			
		||||
			Post(web.Bind(forms.CreateRepoForm{}), repo.ForkPost)
 | 
			
		||||
		if !setting.Repository.DisableForks {
 | 
			
		||||
			m.Combo("/fork", reqRepoCodeReader).Get(repo.Fork).
 | 
			
		||||
				Post(web.Bind(forms.CreateRepoForm{}), repo.ForkPost)
 | 
			
		||||
		}
 | 
			
		||||
		m.Group("/issues", func() {
 | 
			
		||||
			m.Group("/new", func() {
 | 
			
		||||
				m.Combo("").Get(context.RepoRef(), repo.NewIssue).
 | 
			
		||||
| 
						 | 
				
			
			@ -1560,9 +1564,11 @@ func registerRoutes(m *web.Route) {
 | 
			
		|||
			m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.Home)
 | 
			
		||||
		}, repo.SetEditorconfigIfExists)
 | 
			
		||||
 | 
			
		||||
		m.Group("", func() {
 | 
			
		||||
			m.Get("/forks", repo.Forks)
 | 
			
		||||
		}, context.RepoRef(), reqRepoCodeReader)
 | 
			
		||||
		if !setting.Repository.DisableForks {
 | 
			
		||||
			m.Group("", func() {
 | 
			
		||||
				m.Get("/forks", repo.Forks)
 | 
			
		||||
			}, context.RepoRef(), reqRepoCodeReader)
 | 
			
		||||
		}
 | 
			
		||||
		m.Get("/commit/{sha:([a-f0-9]{4,64})}.{ext:patch|diff}", repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff)
 | 
			
		||||
	}, ignSignIn, context.RepoAssignment, context.UnitTypes())
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,9 @@
 | 
			
		|||
						{{if not $.DisableStars}}
 | 
			
		||||
							<a class="text grey flex-text-inline" href="{{.Link}}/stars">{{svg "octicon-star" 16}}{{.NumStars}}</a>
 | 
			
		||||
						{{end}}
 | 
			
		||||
						<a class="text grey flex-text-inline" href="{{.Link}}/forks">{{svg "octicon-git-branch" 16}}{{.NumForks}}</a>
 | 
			
		||||
						{{if not $.DisableForks}}
 | 
			
		||||
							<a class="text grey flex-text-inline" href="{{.Link}}/forks">{{svg "octicon-git-branch" 16}}{{.NumForks}}</a>
 | 
			
		||||
						{{end}}
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				{{$description := .DescriptionHTML $.Context}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,8 +29,10 @@
 | 
			
		|||
				<a class="{{if eq .SortType "moststars"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=moststars&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.moststars"}}</a>
 | 
			
		||||
				<a class="{{if eq .SortType "feweststars"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=feweststars&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.feweststars"}}</a>
 | 
			
		||||
			{{end}}
 | 
			
		||||
			<a class="{{if eq .SortType "mostforks"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=mostforks&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostforks"}}</a>
 | 
			
		||||
			<a class="{{if eq .SortType "fewestforks"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=fewestforks&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.fewestforks"}}</a>
 | 
			
		||||
			{{if not .DisableForks}}
 | 
			
		||||
				<a class="{{if eq .SortType "mostforks"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=mostforks&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostforks"}}</a>
 | 
			
		||||
				<a class="{{if eq .SortType "fewestforks"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=fewestforks&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.fewestforks"}}</a>
 | 
			
		||||
			{{end}}
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,55 +62,8 @@
 | 
			
		|||
					{{if not $.DisableStars}}
 | 
			
		||||
					{{template "repo/star_unstar" $}}
 | 
			
		||||
					{{end}}
 | 
			
		||||
					{{if and (not .IsEmpty) ($.Permission.CanRead $.UnitTypeCode)}}
 | 
			
		||||
						<div class="ui labeled button
 | 
			
		||||
							{{if or (not $.IsSigned) (and (not $.CanSignedUserFork) (not $.UserAndOrgForks))}}
 | 
			
		||||
								disabled
 | 
			
		||||
							{{end}}"
 | 
			
		||||
							{{if not $.IsSigned}}
 | 
			
		||||
								data-tooltip-content="{{ctx.Locale.Tr "repo.fork_guest_user"}}"
 | 
			
		||||
							{{else if and (not $.CanSignedUserFork) (not $.UserAndOrgForks)}}
 | 
			
		||||
								data-tooltip-content="{{ctx.Locale.Tr "repo.fork_from_self"}}"
 | 
			
		||||
							{{end}}
 | 
			
		||||
						>
 | 
			
		||||
							<a class="ui compact{{if $.ShowForkModal}} show-modal{{end}} small basic button"
 | 
			
		||||
								{{if not $.CanSignedUserFork}}
 | 
			
		||||
									{{if gt (len $.UserAndOrgForks) 1}}
 | 
			
		||||
										data-modal="#fork-repo-modal"
 | 
			
		||||
									{{else if eq (len $.UserAndOrgForks) 1}}
 | 
			
		||||
										href="{{AppSubUrl}}/{{(index $.UserAndOrgForks 0).FullName}}"
 | 
			
		||||
									{{/*else is not required here, because the button shouldn't link to any site if you can't create a fork*/}}
 | 
			
		||||
									{{end}}
 | 
			
		||||
								{{else if not $.UserAndOrgForks}}
 | 
			
		||||
									href="{{$.RepoLink}}/fork"
 | 
			
		||||
								{{else}}
 | 
			
		||||
									data-modal="#fork-repo-modal"
 | 
			
		||||
								{{end}}
 | 
			
		||||
							>
 | 
			
		||||
								{{svg "octicon-repo-forked"}}<span class="text">{{ctx.Locale.Tr "repo.fork"}}</span>
 | 
			
		||||
							</a>
 | 
			
		||||
							<div class="ui small modal" id="fork-repo-modal">
 | 
			
		||||
								<div class="header">
 | 
			
		||||
									{{ctx.Locale.Tr "repo.already_forked" .Name}}
 | 
			
		||||
								</div>
 | 
			
		||||
								<div class="content gt-text-left">
 | 
			
		||||
									<div class="ui list">
 | 
			
		||||
										{{range $.UserAndOrgForks}}
 | 
			
		||||
											<div class="ui item gt-py-3">
 | 
			
		||||
												<a href="{{.Link}}">{{svg "octicon-repo-forked" 16 "gt-mr-3"}}{{.FullName}}</a>
 | 
			
		||||
											</div>
 | 
			
		||||
										{{end}}
 | 
			
		||||
									</div>
 | 
			
		||||
									{{if $.CanSignedUserFork}}
 | 
			
		||||
									<div class="divider"></div>
 | 
			
		||||
									<a href="{{$.RepoLink}}/fork">{{ctx.Locale.Tr "repo.fork_to_different_account"}}</a>
 | 
			
		||||
									{{end}}
 | 
			
		||||
								</div>
 | 
			
		||||
							</div>
 | 
			
		||||
							<a class="ui basic label" href="{{.Link}}/forks">
 | 
			
		||||
								{{CountFmt .NumForks}}
 | 
			
		||||
							</a>
 | 
			
		||||
						</div>
 | 
			
		||||
					{{if not $.DisableForks}}
 | 
			
		||||
					{{template "repo/header_fork" $}}
 | 
			
		||||
					{{end}}
 | 
			
		||||
				</div>
 | 
			
		||||
			{{end}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										50
									
								
								templates/repo/header_fork.tmpl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								templates/repo/header_fork.tmpl
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
{{if and (not .IsEmpty) ($.Permission.CanRead $.UnitTypeCode)}}
 | 
			
		||||
	<div class="ui labeled button
 | 
			
		||||
		{{if or (not $.IsSigned) (and (not $.CanSignedUserFork) (not $.UserAndOrgForks))}}
 | 
			
		||||
			disabled
 | 
			
		||||
		{{end}}"
 | 
			
		||||
		{{if not $.IsSigned}}
 | 
			
		||||
			data-tooltip-content="{{ctx.Locale.Tr "repo.fork_guest_user"}}"
 | 
			
		||||
		{{else if and (not $.CanSignedUserFork) (not $.UserAndOrgForks)}}
 | 
			
		||||
			data-tooltip-content="{{ctx.Locale.Tr "repo.fork_from_self"}}"
 | 
			
		||||
		{{end}}
 | 
			
		||||
	>
 | 
			
		||||
		<a class="ui compact{{if $.ShowForkModal}} show-modal{{end}} small basic button"
 | 
			
		||||
			{{if not $.CanSignedUserFork}}
 | 
			
		||||
				{{if gt (len $.UserAndOrgForks) 1}}
 | 
			
		||||
					data-modal="#fork-repo-modal"
 | 
			
		||||
				{{else if eq (len $.UserAndOrgForks) 1}}
 | 
			
		||||
					href="{{AppSubUrl}}/{{(index $.UserAndOrgForks 0).FullName}}"
 | 
			
		||||
				{{/*else is not required here, because the button shouldn't link to any site if you can't create a fork*/}}
 | 
			
		||||
				{{end}}
 | 
			
		||||
			{{else if not $.UserAndOrgForks}}
 | 
			
		||||
				href="{{$.RepoLink}}/fork"
 | 
			
		||||
			{{else}}
 | 
			
		||||
				data-modal="#fork-repo-modal"
 | 
			
		||||
			{{end}}
 | 
			
		||||
		>
 | 
			
		||||
			{{svg "octicon-repo-forked"}}<span class="text">{{ctx.Locale.Tr "repo.fork"}}</span>
 | 
			
		||||
		</a>
 | 
			
		||||
		<div class="ui small modal" id="fork-repo-modal">
 | 
			
		||||
			<div class="header">
 | 
			
		||||
				{{ctx.Locale.Tr "repo.already_forked" .Name}}
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="content gt-text-left">
 | 
			
		||||
				<div class="ui list">
 | 
			
		||||
					{{range $.UserAndOrgForks}}
 | 
			
		||||
						<div class="ui item gt-py-3">
 | 
			
		||||
							<a href="{{.Link}}">{{svg "octicon-repo-forked" 16 "gt-mr-3"}}{{.FullName}}</a>
 | 
			
		||||
						</div>
 | 
			
		||||
					{{end}}
 | 
			
		||||
				</div>
 | 
			
		||||
				{{if $.CanSignedUserFork}}
 | 
			
		||||
				<div class="divider"></div>
 | 
			
		||||
				<a href="{{$.RepoLink}}/fork">{{ctx.Locale.Tr "repo.fork_to_different_account"}}</a>
 | 
			
		||||
				{{end}}
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
		<a class="ui basic label" href="{{.Link}}/forks">
 | 
			
		||||
			{{CountFmt .NumForks}}
 | 
			
		||||
		</a>
 | 
			
		||||
	</div>
 | 
			
		||||
{{end}}
 | 
			
		||||
							
								
								
									
										4
									
								
								templates/swagger/v1_json.tmpl
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								templates/swagger/v1_json.tmpl
									
										
									
										generated
									
									
									
								
							| 
						 | 
				
			
			@ -20565,6 +20565,10 @@
 | 
			
		|||
      "description": "GeneralRepoSettings contains global repository settings exposed by API",
 | 
			
		||||
      "type": "object",
 | 
			
		||||
      "properties": {
 | 
			
		||||
        "forks_disabled": {
 | 
			
		||||
          "type": "boolean",
 | 
			
		||||
          "x-go-name": "ForksDisabled"
 | 
			
		||||
        },
 | 
			
		||||
        "http_git_disabled": {
 | 
			
		||||
          "type": "boolean",
 | 
			
		||||
          "x-go-name": "HTTPGitDisabled"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,18 @@
 | 
			
		|||
// Copyright 2017 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
 | 
			
		||||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
package integration
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/modules/test"
 | 
			
		||||
	"code.gitea.io/gitea/routers"
 | 
			
		||||
	"code.gitea.io/gitea/tests"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -16,3 +21,27 @@ func TestCreateForkNoLogin(t *testing.T) {
 | 
			
		|||
	req := NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/forks", &api.CreateForkOption{})
 | 
			
		||||
	MakeRequest(t, req, http.StatusUnauthorized)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAPIDisabledForkRepo(t *testing.T) {
 | 
			
		||||
	onGiteaRun(t, func(t *testing.T, u *url.URL) {
 | 
			
		||||
		defer test.MockVariableValue(&setting.Repository.DisableForks, true)()
 | 
			
		||||
		defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
 | 
			
		||||
 | 
			
		||||
		t.Run("fork listing", func(t *testing.T) {
 | 
			
		||||
			defer tests.PrintCurrentTest(t)()
 | 
			
		||||
 | 
			
		||||
			req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/forks")
 | 
			
		||||
			MakeRequest(t, req, http.StatusNotFound)
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		t.Run("forking", func(t *testing.T) {
 | 
			
		||||
			defer tests.PrintCurrentTest(t)()
 | 
			
		||||
 | 
			
		||||
			session := loginUser(t, "user5")
 | 
			
		||||
			token := getTokenForLoggedInUser(t, session)
 | 
			
		||||
 | 
			
		||||
			req := NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/forks", &api.CreateForkOption{}).AddTokenAuth(token)
 | 
			
		||||
			session.MakeRequest(t, req, http.StatusNotFound)
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
// Copyright 2017 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
 | 
			
		||||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
package integration
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +15,9 @@ import (
 | 
			
		|||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/test"
 | 
			
		||||
	"code.gitea.io/gitea/routers"
 | 
			
		||||
	repo_service "code.gitea.io/gitea/services/repository"
 | 
			
		||||
	"code.gitea.io/gitea/tests"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -119,6 +123,48 @@ func TestRepoFork(t *testing.T) {
 | 
			
		|||
				session.MakeRequest(t, req, http.StatusNotFound)
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		t.Run("DISABLE_FORKS", func(t *testing.T) {
 | 
			
		||||
			defer test.MockVariableValue(&setting.Repository.DisableForks, true)()
 | 
			
		||||
			defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
 | 
			
		||||
 | 
			
		||||
			t.Run("fork button not present", func(t *testing.T) {
 | 
			
		||||
				defer tests.PrintCurrentTest(t)()
 | 
			
		||||
 | 
			
		||||
				// The "Fork" button should not appear on the repo home
 | 
			
		||||
				req := NewRequest(t, "GET", "/user2/repo1")
 | 
			
		||||
				resp := MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
				htmlDoc := NewHTMLParser(t, resp.Body)
 | 
			
		||||
				htmlDoc.AssertElement(t, "[href=/user2/repo1/fork]", false)
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			t.Run("forking by URL", func(t *testing.T) {
 | 
			
		||||
				t.Run("by name", func(t *testing.T) {
 | 
			
		||||
					defer tests.PrintCurrentTest(t)()
 | 
			
		||||
 | 
			
		||||
					// Forking by URL should be Not Found
 | 
			
		||||
					req := NewRequest(t, "GET", "/user2/repo1/fork")
 | 
			
		||||
					session.MakeRequest(t, req, http.StatusNotFound)
 | 
			
		||||
				})
 | 
			
		||||
 | 
			
		||||
				t.Run("by legacy URL", func(t *testing.T) {
 | 
			
		||||
					defer tests.PrintCurrentTest(t)()
 | 
			
		||||
 | 
			
		||||
					// Forking by legacy URL should be Not Found
 | 
			
		||||
					repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // user2/repo1
 | 
			
		||||
					req := NewRequestf(t, "GET", "/repo/fork/%d", repo.ID)
 | 
			
		||||
					session.MakeRequest(t, req, http.StatusNotFound)
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			t.Run("fork listing", func(t *testing.T) {
 | 
			
		||||
				defer tests.PrintCurrentTest(t)()
 | 
			
		||||
 | 
			
		||||
				// Listing the forks should be Not Found, too
 | 
			
		||||
				req := NewRequest(t, "GET", "/user2/repo1/forks")
 | 
			
		||||
				MakeRequest(t, req, http.StatusNotFound)
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue