2014-05-01 11:44:22 +02:00
|
|
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
2018-08-15 08:29:37 +02:00
|
|
|
// Copyright 2018 The Gitea Authors. All rights reserved.
|
2022-11-27 19:20:29 +01:00
|
|
|
// SPDX-License-Identifier: MIT
|
2014-05-01 11:44:22 +02:00
|
|
|
|
2023-07-02 02:59:32 +02:00
|
|
|
package setting
|
2014-05-01 11:44:22 +02:00
|
|
|
|
2014-07-26 08:28:04 +02:00
|
|
|
import (
|
2019-05-30 04:22:26 +02:00
|
|
|
"fmt"
|
2021-04-05 17:30:52 +02:00
|
|
|
"net/http"
|
2021-06-14 19:20:43 +02:00
|
|
|
"strconv"
|
2014-07-26 08:28:04 +02:00
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2016-11-10 17:24:48 +01:00
|
|
|
"code.gitea.io/gitea/models"
|
2021-09-24 13:32:56 +02:00
|
|
|
"code.gitea.io/gitea/models/db"
|
2022-03-29 08:29:02 +02:00
|
|
|
"code.gitea.io/gitea/models/organization"
|
2021-12-10 02:27:50 +01:00
|
|
|
repo_model "code.gitea.io/gitea/models/repo"
|
2021-11-09 20:57:58 +01:00
|
|
|
unit_model "code.gitea.io/gitea/models/unit"
|
2021-11-24 10:49:20 +01:00
|
|
|
user_model "code.gitea.io/gitea/models/user"
|
2016-11-10 17:24:48 +01:00
|
|
|
"code.gitea.io/gitea/modules/base"
|
|
|
|
"code.gitea.io/gitea/modules/context"
|
2019-03-27 10:33:00 +01:00
|
|
|
"code.gitea.io/gitea/modules/git"
|
2021-12-16 16:55:12 +01:00
|
|
|
"code.gitea.io/gitea/modules/indexer/code"
|
|
|
|
"code.gitea.io/gitea/modules/indexer/stats"
|
2021-04-09 00:25:57 +02:00
|
|
|
"code.gitea.io/gitea/modules/lfs"
|
2016-11-10 17:24:48 +01:00
|
|
|
"code.gitea.io/gitea/modules/log"
|
2022-08-25 04:31:57 +02:00
|
|
|
repo_module "code.gitea.io/gitea/modules/repository"
|
2016-11-10 17:24:48 +01:00
|
|
|
"code.gitea.io/gitea/modules/setting"
|
2020-05-21 15:48:01 +02:00
|
|
|
"code.gitea.io/gitea/modules/structs"
|
2021-06-14 19:20:43 +02:00
|
|
|
"code.gitea.io/gitea/modules/util"
|
2018-08-15 08:29:37 +02:00
|
|
|
"code.gitea.io/gitea/modules/validation"
|
2021-01-26 16:36:53 +01:00
|
|
|
"code.gitea.io/gitea/modules/web"
|
2021-12-10 09:14:24 +01:00
|
|
|
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
2021-04-06 21:44:05 +02:00
|
|
|
"code.gitea.io/gitea/services/forms"
|
2021-11-16 16:25:33 +01:00
|
|
|
"code.gitea.io/gitea/services/migrations"
|
2019-10-01 15:40:17 +02:00
|
|
|
mirror_service "code.gitea.io/gitea/services/mirror"
|
2019-10-26 08:54:11 +02:00
|
|
|
repo_service "code.gitea.io/gitea/services/repository"
|
2021-09-08 17:19:30 +02:00
|
|
|
wiki_service "code.gitea.io/gitea/services/wiki"
|
2014-07-26 08:28:04 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2016-11-07 21:58:22 +01:00
|
|
|
tplSettingsOptions base.TplName = "repo/settings/options"
|
|
|
|
tplCollaboration base.TplName = "repo/settings/collaboration"
|
2017-02-21 16:02:10 +01:00
|
|
|
tplBranches base.TplName = "repo/settings/branches"
|
2016-11-07 21:58:22 +01:00
|
|
|
tplGithooks base.TplName = "repo/settings/githooks"
|
|
|
|
tplGithookEdit base.TplName = "repo/settings/githook_edit"
|
|
|
|
tplDeployKeys base.TplName = "repo/settings/deploy_keys"
|
2014-07-26 08:28:04 +02:00
|
|
|
)
|
|
|
|
|
2022-06-12 07:43:27 +02:00
|
|
|
// SettingsCtxData is a middleware that sets all the general context data for the
|
|
|
|
// settings template.
|
|
|
|
func SettingsCtxData(ctx *context.Context) {
|
2023-02-01 23:56:10 +01:00
|
|
|
ctx.Data["Title"] = ctx.Tr("repo.settings.options")
|
2014-08-02 19:47:33 +02:00
|
|
|
ctx.Data["PageIsSettingsOptions"] = true
|
2019-02-22 22:56:05 +01:00
|
|
|
ctx.Data["ForcePrivate"] = setting.Repository.ForcePrivate
|
2021-09-07 17:49:36 +02:00
|
|
|
ctx.Data["MirrorsEnabled"] = setting.Mirror.Enabled
|
2023-05-29 13:32:52 +02:00
|
|
|
ctx.Data["DisableNewPullMirrors"] = setting.Mirror.DisableNewPull
|
2021-09-07 17:49:36 +02:00
|
|
|
ctx.Data["DisableNewPushMirrors"] = setting.Mirror.DisableNewPush
|
2021-06-14 19:20:43 +02:00
|
|
|
ctx.Data["DefaultMirrorInterval"] = setting.Mirror.DefaultInterval
|
2022-06-07 19:40:12 +02:00
|
|
|
ctx.Data["MinimumMirrorInterval"] = setting.Mirror.MinInterval
|
2020-09-19 18:44:55 +02:00
|
|
|
|
2022-01-20 00:26:57 +01:00
|
|
|
signing, _ := asymkey_service.SigningKey(ctx, ctx.Repo.Repository.RepoPath())
|
2020-09-19 18:44:55 +02:00
|
|
|
ctx.Data["SigningKeyAvailable"] = len(signing) > 0
|
|
|
|
ctx.Data["SigningSettings"] = setting.Repository.Signing
|
2021-12-16 16:55:12 +01:00
|
|
|
ctx.Data["CodeIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
2022-06-07 19:40:12 +02:00
|
|
|
|
2022-03-22 08:03:22 +01:00
|
|
|
if ctx.Doer.IsAdmin {
|
2021-12-16 16:55:12 +01:00
|
|
|
if setting.Indexer.RepoIndexerEnabled {
|
2022-05-20 16:08:52 +02:00
|
|
|
status, err := repo_model.GetIndexerStatus(ctx, ctx.Repo.Repository, repo_model.RepoIndexerTypeCode)
|
2021-12-16 16:55:12 +01:00
|
|
|
if err != nil {
|
|
|
|
ctx.ServerError("repo.indexer_status", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ctx.Data["CodeIndexerStatus"] = status
|
|
|
|
}
|
2022-05-20 16:08:52 +02:00
|
|
|
status, err := repo_model.GetIndexerStatus(ctx, ctx.Repo.Repository, repo_model.RepoIndexerTypeStats)
|
2021-12-16 16:55:12 +01:00
|
|
|
if err != nil {
|
|
|
|
ctx.ServerError("repo.indexer_status", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ctx.Data["StatsIndexerStatus"] = status
|
|
|
|
}
|
2022-07-30 18:45:59 +02:00
|
|
|
pushMirrors, _, err := repo_model.GetPushMirrorsByRepoID(ctx, ctx.Repo.Repository.ID, db.ListOptions{})
|
2021-12-10 02:27:50 +01:00
|
|
|
if err != nil {
|
|
|
|
ctx.ServerError("GetPushMirrorsByRepoID", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ctx.Data["PushMirrors"] = pushMirrors
|
2022-06-12 07:43:27 +02:00
|
|
|
}
|
2020-09-19 18:44:55 +02:00
|
|
|
|
2022-06-12 07:43:27 +02:00
|
|
|
// Settings show a repository's settings page
|
|
|
|
func Settings(ctx *context.Context) {
|
2021-04-05 17:30:52 +02:00
|
|
|
ctx.HTML(http.StatusOK, tplSettingsOptions)
|
2014-07-26 08:28:04 +02:00
|
|
|
}
|
|
|
|
|
2016-11-24 08:04:31 +01:00
|
|
|
// SettingsPost response for changes of a repository
|
2021-01-26 16:36:53 +01:00
|
|
|
func SettingsPost(ctx *context.Context) {
|
2021-04-06 21:44:05 +02:00
|
|
|
form := web.GetForm(ctx).(*forms.RepoSettingForm)
|
2014-07-26 08:28:04 +02:00
|
|
|
|
2022-06-07 19:40:12 +02:00
|
|
|
ctx.Data["ForcePrivate"] = setting.Repository.ForcePrivate
|
|
|
|
ctx.Data["MirrorsEnabled"] = setting.Mirror.Enabled
|
2023-05-29 13:32:52 +02:00
|
|
|
ctx.Data["DisableNewPullMirrors"] = setting.Mirror.DisableNewPull
|
2022-06-07 19:40:12 +02:00
|
|
|
ctx.Data["DisableNewPushMirrors"] = setting.Mirror.DisableNewPush
|
|
|
|
ctx.Data["DefaultMirrorInterval"] = setting.Mirror.DefaultInterval
|
|
|
|
ctx.Data["MinimumMirrorInterval"] = setting.Mirror.MinInterval
|
|
|
|
|
|
|
|
signing, _ := asymkey_service.SigningKey(ctx, ctx.Repo.Repository.RepoPath())
|
|
|
|
ctx.Data["SigningKeyAvailable"] = len(signing) > 0
|
|
|
|
ctx.Data["SigningSettings"] = setting.Repository.Signing
|
|
|
|
ctx.Data["CodeIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
|
|
|
|
2015-08-31 07:36:31 +02:00
|
|
|
repo := ctx.Repo.Repository
|
|
|
|
|
2021-08-11 02:31:13 +02:00
|
|
|
switch ctx.FormString("action") {
|
2014-07-26 08:28:04 +02:00
|
|
|
case "update":
|
|
|
|
if ctx.HasError() {
|
2021-04-05 17:30:52 +02:00
|
|
|
ctx.HTML(http.StatusOK, tplSettingsOptions)
|
2014-07-26 08:28:04 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
newRepoName := form.RepoName
|
|
|
|
// Check if repository name has been changed.
|
2015-08-31 07:36:31 +02:00
|
|
|
if repo.LowerName != strings.ToLower(newRepoName) {
|
2019-11-13 08:01:19 +01:00
|
|
|
// Close the GitRepo if open
|
|
|
|
if ctx.Repo.GitRepo != nil {
|
|
|
|
ctx.Repo.GitRepo.Close()
|
|
|
|
ctx.Repo.GitRepo = nil
|
|
|
|
}
|
2023-02-28 23:17:51 +01:00
|
|
|
if err := repo_service.ChangeRepositoryName(ctx, ctx.Doer, repo, newRepoName); err != nil {
|
2015-08-31 07:36:31 +02:00
|
|
|
ctx.Data["Err_RepoName"] = true
|
2015-03-26 22:11:47 +01:00
|
|
|
switch {
|
2021-12-12 16:48:20 +01:00
|
|
|
case repo_model.IsErrRepoAlreadyExist(err):
|
2016-11-07 21:58:22 +01:00
|
|
|
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tplSettingsOptions, &form)
|
2021-11-24 10:49:20 +01:00
|
|
|
case db.IsErrNameReserved(err):
|
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tplSettingsOptions, &form)
|
2021-12-12 16:48:20 +01:00
|
|
|
case repo_model.IsErrRepoFilesAlreadyExist(err):
|
2020-09-25 06:09:23 +02:00
|
|
|
ctx.Data["Err_RepoName"] = true
|
|
|
|
switch {
|
|
|
|
case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
|
|
|
|
ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt_or_delete"), tplSettingsOptions, form)
|
|
|
|
case setting.Repository.AllowAdoptionOfUnadoptedRepositories:
|
|
|
|
ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt"), tplSettingsOptions, form)
|
|
|
|
case setting.Repository.AllowDeleteOfUnadoptedRepositories:
|
|
|
|
ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.delete"), tplSettingsOptions, form)
|
|
|
|
default:
|
|
|
|
ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist"), tplSettingsOptions, form)
|
|
|
|
}
|
2021-11-24 10:49:20 +01:00
|
|
|
case db.IsErrNamePatternNotAllowed(err):
|
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplSettingsOptions, &form)
|
2015-03-26 22:11:47 +01:00
|
|
|
default:
|
2018-01-10 22:34:17 +01:00
|
|
|
ctx.ServerError("ChangeRepositoryName", err)
|
2014-08-24 15:09:05 +02:00
|
|
|
}
|
2014-07-26 08:28:04 +02:00
|
|
|
return
|
|
|
|
}
|
2015-09-01 17:43:53 +02:00
|
|
|
|
2015-08-31 07:36:31 +02:00
|
|
|
log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newRepoName)
|
2014-07-26 08:28:04 +02:00
|
|
|
}
|
2015-08-31 07:36:31 +02:00
|
|
|
// In case it's just a case change.
|
|
|
|
repo.Name = newRepoName
|
|
|
|
repo.LowerName = strings.ToLower(newRepoName)
|
|
|
|
repo.Description = form.Description
|
|
|
|
repo.Website = form.Website
|
2019-11-11 16:15:29 +01:00
|
|
|
repo.IsTemplate = form.Template
|
2015-11-18 21:01:11 +01:00
|
|
|
|
|
|
|
// Visibility of forked repository is forced sync with base repository.
|
|
|
|
if repo.IsFork {
|
2020-06-07 02:45:12 +02:00
|
|
|
form.Private = repo.BaseRepo.IsPrivate || repo.BaseRepo.Owner.Visibility == structs.VisibleTypePrivate
|
2015-11-18 21:01:11 +01:00
|
|
|
}
|
|
|
|
|
2015-08-31 07:36:31 +02:00
|
|
|
visibilityChanged := repo.IsPrivate != form.Private
|
2019-04-11 10:32:42 +02:00
|
|
|
// when ForcePrivate enabled, you could change public repo to private, but only admin users can change private to public
|
2022-03-22 08:03:22 +01:00
|
|
|
if visibilityChanged && setting.Repository.ForcePrivate && !form.Private && !ctx.Doer.IsAdmin {
|
2021-12-14 06:08:09 +01:00
|
|
|
ctx.RenderWithErr(ctx.Tr("form.repository_force_private"), tplSettingsOptions, form)
|
2019-02-22 22:56:05 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-08-31 07:36:31 +02:00
|
|
|
repo.IsPrivate = form.Private
|
2023-02-28 23:17:51 +01:00
|
|
|
if err := repo_service.UpdateRepository(ctx, repo, visibilityChanged); err != nil {
|
2018-01-10 22:34:17 +01:00
|
|
|
ctx.ServerError("UpdateRepository", err)
|
2015-09-01 15:29:52 +02:00
|
|
|
return
|
2014-07-26 08:28:04 +02:00
|
|
|
}
|
2015-12-05 03:30:33 +01:00
|
|
|
log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
2014-07-26 08:28:04 +02:00
|
|
|
|
2016-08-31 01:18:33 +02:00
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
|
|
|
ctx.Redirect(repo.Link() + "/settings")
|
2016-07-17 03:30:43 +02:00
|
|
|
|
2016-08-31 01:18:33 +02:00
|
|
|
case "mirror":
|
2024-01-24 03:32:57 +01:00
|
|
|
if !setting.Mirror.Enabled || !repo.IsMirror || repo.IsArchived {
|
2018-01-10 22:34:17 +01:00
|
|
|
ctx.NotFound("", nil)
|
2016-08-31 01:18:33 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-05-15 21:02:10 +02:00
|
|
|
pullMirror, err := repo_model.GetMirrorByRepoID(ctx, ctx.Repo.Repository.ID)
|
|
|
|
if err == repo_model.ErrMirrorNotExist {
|
|
|
|
ctx.NotFound("", nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
ctx.ServerError("GetMirrorByRepoID", err)
|
|
|
|
return
|
|
|
|
}
|
2019-03-25 22:51:55 +01:00
|
|
|
// This section doesn't require repo_name/RepoName to be set in the form, don't show it
|
|
|
|
// as an error on the UI for this action
|
|
|
|
ctx.Data["Err_RepoName"] = nil
|
|
|
|
|
2017-04-08 17:27:26 +02:00
|
|
|
interval, err := time.ParseDuration(form.Interval)
|
2019-01-26 09:26:23 +01:00
|
|
|
if err != nil || (interval != 0 && interval < setting.Mirror.MinInterval) {
|
2019-03-25 22:51:55 +01:00
|
|
|
ctx.Data["Err_Interval"] = true
|
2017-04-08 17:27:26 +02:00
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form)
|
2022-06-07 19:40:12 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-05-15 21:02:10 +02:00
|
|
|
pullMirror.EnablePrune = form.EnablePrune
|
|
|
|
pullMirror.Interval = interval
|
|
|
|
pullMirror.ScheduleNextUpdate()
|
|
|
|
if err := repo_model.UpdateMirror(ctx, pullMirror); err != nil {
|
2022-06-07 19:40:12 +02:00
|
|
|
ctx.ServerError("UpdateMirror", err)
|
|
|
|
return
|
2014-07-26 08:28:04 +02:00
|
|
|
}
|
2019-04-12 22:52:57 +02:00
|
|
|
|
2023-05-15 21:02:10 +02:00
|
|
|
u, err := git.GetRemoteURL(ctx, ctx.Repo.Repository.RepoPath(), pullMirror.GetRemoteName())
|
2022-06-11 15:50:14 +02:00
|
|
|
if err != nil {
|
|
|
|
ctx.Data["Err_MirrorAddress"] = true
|
|
|
|
handleSettingRemoteAddrError(ctx, err, form)
|
|
|
|
return
|
|
|
|
}
|
2021-06-14 19:20:43 +02:00
|
|
|
if u.User != nil && form.MirrorPassword == "" && form.MirrorUsername == u.User.Username() {
|
|
|
|
form.MirrorPassword, _ = u.User.Password()
|
2021-05-31 12:46:20 +02:00
|
|
|
}
|
|
|
|
|
2022-08-21 20:23:50 +02:00
|
|
|
address, err := forms.ParseRemoteAddr(form.MirrorAddress, form.MirrorUsername, form.MirrorPassword)
|
|
|
|
if err == nil {
|
|
|
|
err = migrations.IsMigrateURLAllowed(address, ctx.Doer)
|
|
|
|
}
|
2021-03-15 22:52:11 +01:00
|
|
|
if err != nil {
|
2019-04-12 22:52:57 +02:00
|
|
|
ctx.Data["Err_MirrorAddress"] = true
|
2021-04-09 00:25:57 +02:00
|
|
|
handleSettingRemoteAddrError(ctx, err, form)
|
2019-04-12 22:52:57 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-05-15 21:02:10 +02:00
|
|
|
if err := mirror_service.UpdateAddress(ctx, pullMirror, address); err != nil {
|
2020-09-28 21:00:52 +02:00
|
|
|
ctx.ServerError("UpdateAddress", err)
|
2016-08-31 01:18:33 +02:00
|
|
|
return
|
|
|
|
}
|
2014-07-26 08:28:04 +02:00
|
|
|
|
2023-09-16 18:03:02 +02:00
|
|
|
remoteAddress, err := util.SanitizeURL(form.MirrorAddress)
|
|
|
|
if err != nil {
|
|
|
|
ctx.ServerError("SanitizeURL", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
pullMirror.RemoteAddress = remoteAddress
|
|
|
|
|
2021-04-09 00:25:57 +02:00
|
|
|
form.LFS = form.LFS && setting.LFS.StartServer
|
|
|
|
|
|
|
|
if len(form.LFSEndpoint) > 0 {
|
|
|
|
ep := lfs.DetermineEndpoint("", form.LFSEndpoint)
|
|
|
|
if ep == nil {
|
|
|
|
ctx.Data["Err_LFSEndpoint"] = true
|
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_lfs_endpoint"), tplSettingsOptions, &form)
|
|
|
|
return
|
|
|
|
}
|
2022-03-22 08:03:22 +01:00
|
|
|
err = migrations.IsMigrateURLAllowed(ep.String(), ctx.Doer)
|
2021-04-09 00:25:57 +02:00
|
|
|
if err != nil {
|
|
|
|
ctx.Data["Err_LFSEndpoint"] = true
|
|
|
|
handleSettingRemoteAddrError(ctx, err, form)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-15 21:02:10 +02:00
|
|
|
pullMirror.LFS = form.LFS
|
|
|
|
pullMirror.LFSEndpoint = form.LFSEndpoint
|
|
|
|
if err := repo_model.UpdateMirror(ctx, pullMirror); err != nil {
|
2021-04-09 00:25:57 +02:00
|
|
|
ctx.ServerError("UpdateMirror", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-08-02 19:47:33 +02:00
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
2016-07-15 15:53:43 +02:00
|
|
|
ctx.Redirect(repo.Link() + "/settings")
|
2015-12-05 03:30:33 +01:00
|
|
|
|
2016-08-31 01:18:33 +02:00
|
|
|
case "mirror-sync":
|
2024-01-24 03:32:57 +01:00
|
|
|
if !setting.Mirror.Enabled || !repo.IsMirror || repo.IsArchived {
|
2018-01-10 22:34:17 +01:00
|
|
|
ctx.NotFound("", nil)
|
2016-08-31 01:18:33 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-08-27 04:24:45 +02:00
|
|
|
mirror_service.AddPullMirrorToQueue(repo.ID)
|
2019-10-01 15:40:17 +02:00
|
|
|
|
2023-10-02 16:52:18 +02:00
|
|
|
ctx.Flash.Info(ctx.Tr("repo.settings.pull_mirror_sync_in_progress", repo.OriginalURL))
|
2016-08-31 01:18:33 +02:00
|
|
|
ctx.Redirect(repo.Link() + "/settings")
|
|
|
|
|
2021-06-14 19:20:43 +02:00
|
|
|
case "push-mirror-sync":
|
2021-09-07 17:49:36 +02:00
|
|
|
if !setting.Mirror.Enabled {
|
|
|
|
ctx.NotFound("", nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-07-30 18:45:59 +02:00
|
|
|
m, err := selectPushMirrorByForm(ctx, form, repo)
|
2021-06-14 19:20:43 +02:00
|
|
|
if err != nil {
|
|
|
|
ctx.NotFound("", nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-08-27 04:24:45 +02:00
|
|
|
mirror_service.AddPushMirrorToQueue(m.ID)
|
2021-06-14 19:20:43 +02:00
|
|
|
|
2023-10-02 16:52:18 +02:00
|
|
|
ctx.Flash.Info(ctx.Tr("repo.settings.push_mirror_sync_in_progress", m.RemoteAddress))
|
2021-06-14 19:20:43 +02:00
|
|
|
ctx.Redirect(repo.Link() + "/settings")
|
|
|
|
|
2023-08-01 18:00:59 +02:00
|
|
|
case "push-mirror-update":
|
2024-01-24 03:32:57 +01:00
|
|
|
if !setting.Mirror.Enabled || repo.IsArchived {
|
2023-08-01 18:00:59 +02:00
|
|
|
ctx.NotFound("", nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// This section doesn't require repo_name/RepoName to be set in the form, don't show it
|
|
|
|
// as an error on the UI for this action
|
|
|
|
ctx.Data["Err_RepoName"] = nil
|
|
|
|
|
|
|
|
interval, err := time.ParseDuration(form.PushMirrorInterval)
|
|
|
|
if err != nil || (interval != 0 && interval < setting.Mirror.MinInterval) {
|
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &forms.RepoSettingForm{})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
id, err := strconv.ParseInt(form.PushMirrorID, 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
ctx.ServerError("UpdatePushMirrorIntervalPushMirrorID", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
m := &repo_model.PushMirror{
|
|
|
|
ID: id,
|
|
|
|
Interval: interval,
|
|
|
|
}
|
|
|
|
if err := repo_model.UpdatePushMirrorInterval(ctx, m); err != nil {
|
|
|
|
ctx.ServerError("UpdatePushMirrorInterval", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Background why we are adding it to Queue
|
|
|
|
// If we observed its implementation in the context of `push-mirror-sync` where it
|
|
|
|
// is evident that pushing to the queue is necessary for updates.
|
|
|
|
// So, there are updates within the given interval, it is necessary to update the queue accordingly.
|
2023-08-27 04:24:45 +02:00
|
|
|
mirror_service.AddPushMirrorToQueue(m.ID)
|
2023-08-01 18:00:59 +02:00
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
|
|
|
ctx.Redirect(repo.Link() + "/settings")
|
|
|
|
|
2021-06-14 19:20:43 +02:00
|
|
|
case "push-mirror-remove":
|
2024-01-24 03:32:57 +01:00
|
|
|
if !setting.Mirror.Enabled || repo.IsArchived {
|
2021-09-07 17:49:36 +02:00
|
|
|
ctx.NotFound("", nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-06-14 19:20:43 +02:00
|
|
|
// This section doesn't require repo_name/RepoName to be set in the form, don't show it
|
|
|
|
// as an error on the UI for this action
|
|
|
|
ctx.Data["Err_RepoName"] = nil
|
|
|
|
|
2022-07-30 18:45:59 +02:00
|
|
|
m, err := selectPushMirrorByForm(ctx, form, repo)
|
2021-06-14 19:20:43 +02:00
|
|
|
if err != nil {
|
|
|
|
ctx.NotFound("", nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-20 00:26:57 +01:00
|
|
|
if err = mirror_service.RemovePushMirrorRemote(ctx, m); err != nil {
|
2021-06-14 19:20:43 +02:00
|
|
|
ctx.ServerError("RemovePushMirrorRemote", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-07-30 18:45:59 +02:00
|
|
|
if err = repo_model.DeletePushMirrors(ctx, repo_model.PushMirrorOptions{ID: m.ID, RepoID: m.RepoID}); err != nil {
|
2021-06-14 19:20:43 +02:00
|
|
|
ctx.ServerError("DeletePushMirrorByID", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
|
|
|
ctx.Redirect(repo.Link() + "/settings")
|
|
|
|
|
|
|
|
case "push-mirror-add":
|
2024-01-24 03:32:57 +01:00
|
|
|
if setting.Mirror.DisableNewPush || repo.IsArchived {
|
2021-09-07 17:49:36 +02:00
|
|
|
ctx.NotFound("", nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-06-14 19:20:43 +02:00
|
|
|
// This section doesn't require repo_name/RepoName to be set in the form, don't show it
|
|
|
|
// as an error on the UI for this action
|
|
|
|
ctx.Data["Err_RepoName"] = nil
|
|
|
|
|
|
|
|
interval, err := time.ParseDuration(form.PushMirrorInterval)
|
|
|
|
if err != nil || (interval != 0 && interval < setting.Mirror.MinInterval) {
|
|
|
|
ctx.Data["Err_PushMirrorInterval"] = true
|
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
address, err := forms.ParseRemoteAddr(form.PushMirrorAddress, form.PushMirrorUsername, form.PushMirrorPassword)
|
|
|
|
if err == nil {
|
2022-03-22 08:03:22 +01:00
|
|
|
err = migrations.IsMigrateURLAllowed(address, ctx.Doer)
|
2021-06-14 19:20:43 +02:00
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
ctx.Data["Err_PushMirrorAddress"] = true
|
|
|
|
handleSettingRemoteAddrError(ctx, err, form)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-26 05:10:10 +01:00
|
|
|
remoteSuffix, err := util.CryptoRandomString(10)
|
2021-06-14 19:20:43 +02:00
|
|
|
if err != nil {
|
|
|
|
ctx.ServerError("RandomString", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-09-16 18:03:02 +02:00
|
|
|
remoteAddress, err := util.SanitizeURL(form.PushMirrorAddress)
|
|
|
|
if err != nil {
|
|
|
|
ctx.ServerError("SanitizeURL", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-10 02:27:50 +01:00
|
|
|
m := &repo_model.PushMirror{
|
2023-09-16 18:03:02 +02:00
|
|
|
RepoID: repo.ID,
|
|
|
|
Repo: repo,
|
|
|
|
RemoteName: fmt.Sprintf("remote_mirror_%s", remoteSuffix),
|
|
|
|
SyncOnCommit: form.PushMirrorSyncOnCommit,
|
|
|
|
Interval: interval,
|
|
|
|
RemoteAddress: remoteAddress,
|
2021-06-14 19:20:43 +02:00
|
|
|
}
|
2023-12-25 21:25:29 +01:00
|
|
|
if err := db.Insert(ctx, m); err != nil {
|
2021-06-14 19:20:43 +02:00
|
|
|
ctx.ServerError("InsertPushMirror", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-20 00:26:57 +01:00
|
|
|
if err := mirror_service.AddPushMirrorRemote(ctx, m, address); err != nil {
|
2022-07-30 18:45:59 +02:00
|
|
|
if err := repo_model.DeletePushMirrors(ctx, repo_model.PushMirrorOptions{ID: m.ID, RepoID: m.RepoID}); err != nil {
|
|
|
|
log.Error("DeletePushMirrors %v", err)
|
2021-06-14 19:20:43 +02:00
|
|
|
}
|
|
|
|
ctx.ServerError("AddPushMirrorRemote", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
|
|
|
ctx.Redirect(repo.Link() + "/settings")
|
|
|
|
|
2015-12-05 03:30:33 +01:00
|
|
|
case "advanced":
|
2021-03-16 02:00:52 +01:00
|
|
|
var repoChanged bool
|
2021-12-10 02:27:50 +01:00
|
|
|
var units []repo_model.RepoUnit
|
2021-11-09 20:57:58 +01:00
|
|
|
var deleteUnitTypes []unit_model.Type
|
2017-02-04 16:53:46 +01:00
|
|
|
|
2019-03-25 22:51:55 +01:00
|
|
|
// This section doesn't require repo_name/RepoName to be set in the form, don't show it
|
|
|
|
// as an error on the UI for this action
|
|
|
|
ctx.Data["Err_RepoName"] = nil
|
|
|
|
|
2021-03-16 02:00:52 +01:00
|
|
|
if repo.CloseIssuesViaCommitInAnyBranch != form.EnableCloseIssuesViaCommitInAnyBranch {
|
|
|
|
repo.CloseIssuesViaCommitInAnyBranch = form.EnableCloseIssuesViaCommitInAnyBranch
|
|
|
|
repoChanged = true
|
|
|
|
}
|
|
|
|
|
2022-12-12 06:29:27 +01:00
|
|
|
if form.EnableCode && !unit_model.TypeCode.UnitGlobalDisabled() {
|
|
|
|
units = append(units, repo_model.RepoUnit{
|
|
|
|
RepoID: repo.ID,
|
|
|
|
Type: unit_model.TypeCode,
|
|
|
|
})
|
|
|
|
} else if !unit_model.TypeCode.UnitGlobalDisabled() {
|
|
|
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeCode)
|
|
|
|
}
|
|
|
|
|
2021-11-09 20:57:58 +01:00
|
|
|
if form.EnableWiki && form.EnableExternalWiki && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
|
2020-01-17 08:34:37 +01:00
|
|
|
if !validation.IsValidExternalURL(form.ExternalWikiURL) {
|
|
|
|
ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error"))
|
|
|
|
ctx.Redirect(repo.Link() + "/settings")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-10 02:27:50 +01:00
|
|
|
units = append(units, repo_model.RepoUnit{
|
2020-01-17 08:34:37 +01:00
|
|
|
RepoID: repo.ID,
|
2021-11-09 20:57:58 +01:00
|
|
|
Type: unit_model.TypeExternalWiki,
|
2021-12-10 02:27:50 +01:00
|
|
|
Config: &repo_model.ExternalWikiConfig{
|
2020-01-17 08:34:37 +01:00
|
|
|
ExternalWikiURL: form.ExternalWikiURL,
|
|
|
|
},
|
|
|
|
})
|
2021-11-09 20:57:58 +01:00
|
|
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki)
|
|
|
|
} else if form.EnableWiki && !form.EnableExternalWiki && !unit_model.TypeWiki.UnitGlobalDisabled() {
|
2023-12-20 21:44:55 +01:00
|
|
|
var wikiPermissions repo_model.UnitAccessMode
|
|
|
|
if form.GloballyWriteableWiki {
|
|
|
|
wikiPermissions = repo_model.UnitAccessModeWrite
|
|
|
|
} else {
|
|
|
|
wikiPermissions = repo_model.UnitAccessModeRead
|
|
|
|
}
|
2021-12-10 02:27:50 +01:00
|
|
|
units = append(units, repo_model.RepoUnit{
|
2023-12-20 21:44:55 +01:00
|
|
|
RepoID: repo.ID,
|
|
|
|
Type: unit_model.TypeWiki,
|
|
|
|
Config: new(repo_model.UnitConfig),
|
|
|
|
DefaultPermissions: wikiPermissions,
|
2017-02-04 16:53:46 +01:00
|
|
|
})
|
2021-11-09 20:57:58 +01:00
|
|
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
|
2020-01-17 08:34:37 +01:00
|
|
|
} else {
|
2021-11-09 20:57:58 +01:00
|
|
|
if !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
|
|
|
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
|
2020-01-17 08:34:37 +01:00
|
|
|
}
|
2021-11-09 20:57:58 +01:00
|
|
|
if !unit_model.TypeWiki.UnitGlobalDisabled() {
|
|
|
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki)
|
2017-02-04 16:53:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-09 20:57:58 +01:00
|
|
|
if form.EnableIssues && form.EnableExternalTracker && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
|
2020-01-17 08:34:37 +01:00
|
|
|
if !validation.IsValidExternalURL(form.ExternalTrackerURL) {
|
|
|
|
ctx.Flash.Error(ctx.Tr("repo.settings.external_tracker_url_error"))
|
|
|
|
ctx.Redirect(repo.Link() + "/settings")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(form.TrackerURLFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(form.TrackerURLFormat) {
|
|
|
|
ctx.Flash.Error(ctx.Tr("repo.settings.tracker_url_format_error"))
|
|
|
|
ctx.Redirect(repo.Link() + "/settings")
|
|
|
|
return
|
|
|
|
}
|
2021-12-10 02:27:50 +01:00
|
|
|
units = append(units, repo_model.RepoUnit{
|
2020-01-17 08:34:37 +01:00
|
|
|
RepoID: repo.ID,
|
2021-11-09 20:57:58 +01:00
|
|
|
Type: unit_model.TypeExternalTracker,
|
2021-12-10 02:27:50 +01:00
|
|
|
Config: &repo_model.ExternalTrackerConfig{
|
2022-06-10 07:39:53 +02:00
|
|
|
ExternalTrackerURL: form.ExternalTrackerURL,
|
|
|
|
ExternalTrackerFormat: form.TrackerURLFormat,
|
|
|
|
ExternalTrackerStyle: form.TrackerIssueStyle,
|
|
|
|
ExternalTrackerRegexpPattern: form.ExternalTrackerRegexpPattern,
|
2020-01-17 08:34:37 +01:00
|
|
|
},
|
|
|
|
})
|
2021-11-09 20:57:58 +01:00
|
|
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
|
|
|
|
} else if form.EnableIssues && !form.EnableExternalTracker && !unit_model.TypeIssues.UnitGlobalDisabled() {
|
2021-12-10 02:27:50 +01:00
|
|
|
units = append(units, repo_model.RepoUnit{
|
2020-01-17 08:34:37 +01:00
|
|
|
RepoID: repo.ID,
|
2021-11-09 20:57:58 +01:00
|
|
|
Type: unit_model.TypeIssues,
|
2021-12-10 02:27:50 +01:00
|
|
|
Config: &repo_model.IssuesConfig{
|
2020-01-17 08:34:37 +01:00
|
|
|
EnableTimetracker: form.EnableTimetracker,
|
|
|
|
AllowOnlyContributorsToTrackTime: form.AllowOnlyContributorsToTrackTime,
|
|
|
|
EnableDependencies: form.EnableIssueDependencies,
|
|
|
|
},
|
|
|
|
})
|
2021-11-09 20:57:58 +01:00
|
|
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
2020-01-17 08:34:37 +01:00
|
|
|
} else {
|
2021-11-09 20:57:58 +01:00
|
|
|
if !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
|
|
|
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
2020-01-17 08:34:37 +01:00
|
|
|
}
|
2021-11-09 20:57:58 +01:00
|
|
|
if !unit_model.TypeIssues.UnitGlobalDisabled() {
|
|
|
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
|
2017-02-04 16:53:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-09 20:57:58 +01:00
|
|
|
if form.EnableProjects && !unit_model.TypeProjects.UnitGlobalDisabled() {
|
2021-12-10 02:27:50 +01:00
|
|
|
units = append(units, repo_model.RepoUnit{
|
2020-08-17 05:07:38 +02:00
|
|
|
RepoID: repo.ID,
|
2021-11-09 20:57:58 +01:00
|
|
|
Type: unit_model.TypeProjects,
|
2020-08-17 05:07:38 +02:00
|
|
|
})
|
2021-11-09 20:57:58 +01:00
|
|
|
} else if !unit_model.TypeProjects.UnitGlobalDisabled() {
|
|
|
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeProjects)
|
2020-08-17 05:07:38 +02:00
|
|
|
}
|
|
|
|
|
2023-02-01 02:31:19 +01:00
|
|
|
if form.EnableReleases && !unit_model.TypeReleases.UnitGlobalDisabled() {
|
|
|
|
units = append(units, repo_model.RepoUnit{
|
|
|
|
RepoID: repo.ID,
|
|
|
|
Type: unit_model.TypeReleases,
|
|
|
|
})
|
|
|
|
} else if !unit_model.TypeReleases.UnitGlobalDisabled() {
|
|
|
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeReleases)
|
|
|
|
}
|
|
|
|
|
2022-07-26 16:34:14 +02:00
|
|
|
if form.EnablePackages && !unit_model.TypePackages.UnitGlobalDisabled() {
|
2022-05-08 17:51:50 +02:00
|
|
|
units = append(units, repo_model.RepoUnit{
|
|
|
|
RepoID: repo.ID,
|
|
|
|
Type: unit_model.TypePackages,
|
|
|
|
})
|
|
|
|
} else if !unit_model.TypePackages.UnitGlobalDisabled() {
|
|
|
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePackages)
|
|
|
|
}
|
|
|
|
|
Implement actions (#21937)
Close #13539.
Co-authored by: @lunny @appleboy @fuxiaohei and others.
Related projects:
- https://gitea.com/gitea/actions-proto-def
- https://gitea.com/gitea/actions-proto-go
- https://gitea.com/gitea/act
- https://gitea.com/gitea/act_runner
### Summary
The target of this PR is to bring a basic implementation of "Actions",
an internal CI/CD system of Gitea. That means even though it has been
merged, the state of the feature is **EXPERIMENTAL**, and please note
that:
- It is disabled by default;
- It shouldn't be used in a production environment currently;
- It shouldn't be used in a public Gitea instance currently;
- Breaking changes may be made before it's stable.
**Please comment on #13539 if you have any different product design
ideas**, all decisions reached there will be adopted here. But in this
PR, we don't talk about **naming, feature-creep or alternatives**.
### ⚠️ Breaking
`gitea-actions` will become a reserved user name. If a user with the
name already exists in the database, it is recommended to rename it.
### Some important reviews
- What is `DEFAULT_ACTIONS_URL` in `app.ini` for?
- https://github.com/go-gitea/gitea/pull/21937#discussion_r1055954954
- Why the api for runners is not under the normal `/api/v1` prefix?
- https://github.com/go-gitea/gitea/pull/21937#discussion_r1061173592
- Why DBFS?
- https://github.com/go-gitea/gitea/pull/21937#discussion_r1061301178
- Why ignore events triggered by `gitea-actions` bot?
- https://github.com/go-gitea/gitea/pull/21937#discussion_r1063254103
- Why there's no permission control for actions?
- https://github.com/go-gitea/gitea/pull/21937#discussion_r1090229868
### What it looks like
<details>
#### Manage runners
<img width="1792" alt="image"
src="https://user-images.githubusercontent.com/9418365/205870657-c72f590e-2e08-4cd4-be7f-2e0abb299bbf.png">
#### List runs
<img width="1792" alt="image"
src="https://user-images.githubusercontent.com/9418365/205872794-50fde990-2b45-48c1-a178-908e4ec5b627.png">
#### View logs
<img width="1792" alt="image"
src="https://user-images.githubusercontent.com/9418365/205872501-9b7b9000-9542-4991-8f55-18ccdada77c3.png">
</details>
### How to try it
<details>
#### 1. Start Gitea
Clone this branch and [install from
source](https://docs.gitea.io/en-us/install-from-source).
Add additional configurations in `app.ini` to enable Actions:
```ini
[actions]
ENABLED = true
```
Start it.
If all is well, you'll see the management page of runners:
<img width="1792" alt="image"
src="https://user-images.githubusercontent.com/9418365/205877365-8e30a780-9b10-4154-b3e8-ee6c3cb35a59.png">
#### 2. Start runner
Clone the [act_runner](https://gitea.com/gitea/act_runner), and follow
the
[README](https://gitea.com/gitea/act_runner/src/branch/main/README.md)
to start it.
If all is well, you'll see a new runner has been added:
<img width="1792" alt="image"
src="https://user-images.githubusercontent.com/9418365/205878000-216f5937-e696-470d-b66c-8473987d91c3.png">
#### 3. Enable actions for a repo
Create a new repo or open an existing one, check the `Actions` checkbox
in settings and submit.
<img width="1792" alt="image"
src="https://user-images.githubusercontent.com/9418365/205879705-53e09208-73c0-4b3e-a123-2dcf9aba4b9c.png">
<img width="1792" alt="image"
src="https://user-images.githubusercontent.com/9418365/205879383-23f3d08f-1a85-41dd-a8b3-54e2ee6453e8.png">
If all is well, you'll see a new tab "Actions":
<img width="1792" alt="image"
src="https://user-images.githubusercontent.com/9418365/205881648-a8072d8c-5803-4d76-b8a8-9b2fb49516c1.png">
#### 4. Upload workflow files
Upload some workflow files to `.gitea/workflows/xxx.yaml`, you can
follow the [quickstart](https://docs.github.com/en/actions/quickstart)
of GitHub Actions. Yes, Gitea Actions is compatible with GitHub Actions
in most cases, you can use the same demo:
```yaml
name: GitHub Actions Demo
run-name: ${{ github.actor }} is testing out GitHub Actions 🚀
on: [push]
jobs:
Explore-GitHub-Actions:
runs-on: ubuntu-latest
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
- run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
- name: Check out repository code
uses: actions/checkout@v3
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
- name: List files in the repository
run: |
ls ${{ github.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."
```
If all is well, you'll see a new run in `Actions` tab:
<img width="1792" alt="image"
src="https://user-images.githubusercontent.com/9418365/205884473-79a874bc-171b-4aaf-acd5-0241a45c3b53.png">
#### 5. Check the logs of jobs
Click a run and you'll see the logs:
<img width="1792" alt="image"
src="https://user-images.githubusercontent.com/9418365/205884800-994b0374-67f7-48ff-be9a-4c53f3141547.png">
#### 6. Go on
You can try more examples in [the
documents](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions)
of GitHub Actions, then you might find a lot of bugs.
Come on, PRs are welcome.
</details>
See also: [Feature Preview: Gitea
Actions](https://blog.gitea.io/2022/12/feature-preview-gitea-actions/)
---------
Co-authored-by: a1012112796 <1012112796@qq.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: ChristopherHX <christopher.homberger@web.de>
Co-authored-by: John Olheiser <john.olheiser@gmail.com>
2023-01-31 02:45:19 +01:00
|
|
|
if form.EnableActions && !unit_model.TypeActions.UnitGlobalDisabled() {
|
|
|
|
units = append(units, repo_model.RepoUnit{
|
|
|
|
RepoID: repo.ID,
|
|
|
|
Type: unit_model.TypeActions,
|
|
|
|
})
|
|
|
|
} else if !unit_model.TypeActions.UnitGlobalDisabled() {
|
|
|
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeActions)
|
|
|
|
}
|
|
|
|
|
2021-11-09 20:57:58 +01:00
|
|
|
if form.EnablePulls && !unit_model.TypePullRequests.UnitGlobalDisabled() {
|
2021-12-10 02:27:50 +01:00
|
|
|
units = append(units, repo_model.RepoUnit{
|
2017-02-04 16:53:46 +01:00
|
|
|
RepoID: repo.ID,
|
2021-11-09 20:57:58 +01:00
|
|
|
Type: unit_model.TypePullRequests,
|
2021-12-10 02:27:50 +01:00
|
|
|
Config: &repo_model.PullRequestsConfig{
|
2021-07-13 01:26:25 +02:00
|
|
|
IgnoreWhitespaceConflicts: form.PullsIgnoreWhitespace,
|
|
|
|
AllowMerge: form.PullsAllowMerge,
|
|
|
|
AllowRebase: form.PullsAllowRebase,
|
|
|
|
AllowRebaseMerge: form.PullsAllowRebaseMerge,
|
|
|
|
AllowSquash: form.PullsAllowSquash,
|
|
|
|
AllowManualMerge: form.PullsAllowManualMerge,
|
|
|
|
AutodetectManualMerge: form.EnableAutodetectManualMerge,
|
2022-03-04 09:30:49 +01:00
|
|
|
AllowRebaseUpdate: form.PullsAllowRebaseUpdate,
|
2021-07-13 01:26:25 +02:00
|
|
|
DefaultDeleteBranchAfterMerge: form.DefaultDeleteBranchAfterMerge,
|
2021-12-10 02:27:50 +01:00
|
|
|
DefaultMergeStyle: repo_model.MergeStyle(form.PullsDefaultMergeStyle),
|
2023-02-13 07:09:52 +01:00
|
|
|
DefaultAllowMaintainerEdit: form.DefaultAllowMaintainerEdit,
|
2018-01-05 19:56:50 +01:00
|
|
|
},
|
2017-02-04 16:53:46 +01:00
|
|
|
})
|
2021-11-09 20:57:58 +01:00
|
|
|
} else if !unit_model.TypePullRequests.UnitGlobalDisabled() {
|
|
|
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePullRequests)
|
2017-02-04 16:53:46 +01:00
|
|
|
}
|
|
|
|
|
2023-05-06 11:39:06 +02:00
|
|
|
if len(units) == 0 {
|
|
|
|
ctx.Flash.Error(ctx.Tr("repo.settings.update_settings_no_unit"))
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-01-22 16:07:17 +01:00
|
|
|
if err := repo_model.UpdateRepositoryUnits(ctx, repo, units, deleteUnitTypes); err != nil {
|
2018-01-10 22:34:17 +01:00
|
|
|
ctx.ServerError("UpdateRepositoryUnits", err)
|
2015-12-05 03:30:33 +01:00
|
|
|
return
|
|
|
|
}
|
2021-03-16 02:00:52 +01:00
|
|
|
if repoChanged {
|
2023-02-28 23:17:51 +01:00
|
|
|
if err := repo_service.UpdateRepository(ctx, repo, false); err != nil {
|
2021-03-16 02:00:52 +01:00
|
|
|
ctx.ServerError("UpdateRepository", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2015-12-05 03:30:33 +01:00
|
|
|
log.Trace("Repository advanced settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
|
|
|
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
|
|
|
2020-09-19 18:44:55 +02:00
|
|
|
case "signing":
|
|
|
|
changed := false
|
2021-12-10 02:27:50 +01:00
|
|
|
trustModel := repo_model.ToTrustModel(form.TrustModel)
|
2020-09-19 18:44:55 +02:00
|
|
|
if trustModel != repo.TrustModel {
|
|
|
|
repo.TrustModel = trustModel
|
|
|
|
changed = true
|
|
|
|
}
|
|
|
|
|
|
|
|
if changed {
|
2023-02-28 23:17:51 +01:00
|
|
|
if err := repo_service.UpdateRepository(ctx, repo, false); err != nil {
|
2020-09-19 18:44:55 +02:00
|
|
|
ctx.ServerError("UpdateRepository", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
log.Trace("Repository signing settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
|
|
|
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
|
|
|
2018-03-27 16:13:20 +02:00
|
|
|
case "admin":
|
2022-03-22 08:03:22 +01:00
|
|
|
if !ctx.Doer.IsAdmin {
|
2021-04-05 17:30:52 +02:00
|
|
|
ctx.Error(http.StatusForbidden)
|
2018-03-27 16:13:20 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if repo.IsFsckEnabled != form.EnableHealthCheck {
|
|
|
|
repo.IsFsckEnabled = form.EnableHealthCheck
|
|
|
|
}
|
|
|
|
|
2023-02-28 23:17:51 +01:00
|
|
|
if err := repo_service.UpdateRepository(ctx, repo, false); err != nil {
|
2019-02-10 20:27:19 +01:00
|
|
|
ctx.ServerError("UpdateRepository", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Trace("Repository admin settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
|
|
|
|
2018-03-27 16:13:20 +02:00
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
|
|
|
2021-12-16 16:55:12 +01:00
|
|
|
case "admin_index":
|
2022-03-22 08:03:22 +01:00
|
|
|
if !ctx.Doer.IsAdmin {
|
2021-12-16 16:55:12 +01:00
|
|
|
ctx.Error(http.StatusForbidden)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch form.RequestReindexType {
|
|
|
|
case "stats":
|
|
|
|
if err := stats.UpdateRepoIndexer(ctx.Repo.Repository); err != nil {
|
|
|
|
ctx.ServerError("UpdateStatsRepondexer", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
case "code":
|
|
|
|
if !setting.Indexer.RepoIndexerEnabled {
|
|
|
|
ctx.Error(http.StatusForbidden)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
code.UpdateRepoIndexer(ctx.Repo.Repository)
|
|
|
|
default:
|
|
|
|
ctx.NotFound("", nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Trace("Repository reindex for %s requested: %s/%s", form.RequestReindexType, ctx.Repo.Owner.Name, repo.Name)
|
|
|
|
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.reindex_requested"))
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
|
|
|
2016-02-14 21:12:00 +01:00
|
|
|
case "convert":
|
2016-03-06 02:45:23 +01:00
|
|
|
if !ctx.Repo.IsOwner() {
|
2021-04-05 17:30:52 +02:00
|
|
|
ctx.Error(http.StatusNotFound)
|
2016-03-06 02:45:23 +01:00
|
|
|
return
|
|
|
|
}
|
2023-11-23 20:24:52 +01:00
|
|
|
if repo.FullName() != form.RepoName {
|
2016-11-07 21:58:22 +01:00
|
|
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
2016-02-14 21:12:00 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-02-14 21:22:36 +01:00
|
|
|
if !repo.IsMirror {
|
2021-04-05 17:30:52 +02:00
|
|
|
ctx.Error(http.StatusNotFound)
|
2016-02-14 21:22:36 +01:00
|
|
|
return
|
|
|
|
}
|
2016-02-14 21:12:00 +01:00
|
|
|
repo.IsMirror = false
|
|
|
|
|
2022-08-25 04:31:57 +02:00
|
|
|
if _, err := repo_module.CleanUpMigrateInfo(ctx, repo); err != nil {
|
2018-01-10 22:34:17 +01:00
|
|
|
ctx.ServerError("CleanUpMigrateInfo", err)
|
2016-02-14 21:12:00 +01:00
|
|
|
return
|
2023-09-29 14:12:54 +02:00
|
|
|
} else if err = repo_model.DeleteMirrorByRepoID(ctx, ctx.Repo.Repository.ID); err != nil {
|
2018-01-10 22:34:17 +01:00
|
|
|
ctx.ServerError("DeleteMirrorByRepoID", err)
|
2016-02-14 21:12:00 +01:00
|
|
|
return
|
|
|
|
}
|
2020-07-02 16:09:09 +02:00
|
|
|
log.Trace("Repository converted from mirror to regular: %s", repo.FullName())
|
2016-02-14 21:12:00 +01:00
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.convert_succeed"))
|
2020-07-02 16:09:09 +02:00
|
|
|
ctx.Redirect(repo.Link())
|
|
|
|
|
|
|
|
case "convert_fork":
|
|
|
|
if !ctx.Repo.IsOwner() {
|
2021-04-05 17:30:52 +02:00
|
|
|
ctx.Error(http.StatusNotFound)
|
2020-07-02 16:09:09 +02:00
|
|
|
return
|
|
|
|
}
|
2023-02-18 13:11:03 +01:00
|
|
|
if err := repo.LoadOwner(ctx); err != nil {
|
2020-07-02 16:09:09 +02:00
|
|
|
ctx.ServerError("Convert Fork", err)
|
|
|
|
return
|
|
|
|
}
|
2023-11-23 20:24:52 +01:00
|
|
|
if repo.FullName() != form.RepoName {
|
2020-07-02 16:09:09 +02:00
|
|
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if !repo.IsFork {
|
2021-04-05 17:30:52 +02:00
|
|
|
ctx.Error(http.StatusNotFound)
|
2020-07-02 16:09:09 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if !ctx.Repo.Owner.CanCreateRepo() {
|
2022-01-02 03:38:07 +01:00
|
|
|
maxCreationLimit := ctx.Repo.Owner.MaxCreationLimit()
|
2022-01-02 04:33:57 +01:00
|
|
|
msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit)
|
|
|
|
ctx.Flash.Error(msg)
|
2020-07-02 16:09:09 +02:00
|
|
|
ctx.Redirect(repo.Link() + "/settings")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-02-28 23:17:51 +01:00
|
|
|
if err := repo_service.ConvertForkToNormalRepository(ctx, repo); err != nil {
|
2021-09-14 19:07:08 +02:00
|
|
|
log.Error("Unable to convert repository %-v from fork. Error: %v", repo, err)
|
2020-07-02 16:09:09 +02:00
|
|
|
ctx.ServerError("Convert Fork", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Trace("Repository converted from fork to regular: %s", repo.FullName())
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.convert_fork_succeed"))
|
|
|
|
ctx.Redirect(repo.Link())
|
2016-02-14 21:12:00 +01:00
|
|
|
|
2014-07-26 08:28:04 +02:00
|
|
|
case "transfer":
|
2016-03-06 02:45:23 +01:00
|
|
|
if !ctx.Repo.IsOwner() {
|
2021-04-05 17:30:52 +02:00
|
|
|
ctx.Error(http.StatusNotFound)
|
2016-03-06 02:45:23 +01:00
|
|
|
return
|
|
|
|
}
|
2023-11-23 20:24:52 +01:00
|
|
|
if repo.FullName() != form.RepoName {
|
2016-11-07 21:58:22 +01:00
|
|
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
2014-07-26 08:28:04 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-05-20 16:08:52 +02:00
|
|
|
newOwner, err := user_model.GetUserByName(ctx, ctx.FormString("new_owner_name"))
|
2014-07-26 08:28:04 +02:00
|
|
|
if err != nil {
|
2021-11-24 10:49:20 +01:00
|
|
|
if user_model.IsErrUserNotExist(err) {
|
2020-01-31 16:49:04 +01:00
|
|
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil)
|
|
|
|
return
|
|
|
|
}
|
2018-01-10 22:34:17 +01:00
|
|
|
ctx.ServerError("IsUserExist", err)
|
2014-07-26 08:28:04 +02:00
|
|
|
return
|
2015-03-06 01:20:27 +01:00
|
|
|
}
|
|
|
|
|
2021-11-24 10:49:20 +01:00
|
|
|
if newOwner.Type == user_model.UserTypeOrganization {
|
2023-10-03 12:30:41 +02:00
|
|
|
if !ctx.Doer.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !organization.OrgFromUser(newOwner).HasMemberWithUserID(ctx, ctx.Doer.ID) {
|
2020-05-21 15:48:01 +02:00
|
|
|
// The user shouldn't know about this organization
|
|
|
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-13 08:01:19 +01:00
|
|
|
// Close the GitRepo if open
|
|
|
|
if ctx.Repo.GitRepo != nil {
|
|
|
|
ctx.Repo.GitRepo.Close()
|
|
|
|
ctx.Repo.GitRepo = nil
|
|
|
|
}
|
2021-03-01 01:47:30 +01:00
|
|
|
|
2022-12-10 03:46:31 +01:00
|
|
|
if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, repo, nil); err != nil {
|
2021-12-12 16:48:20 +01:00
|
|
|
if repo_model.IsErrRepoAlreadyExist(err) {
|
2016-11-07 21:58:22 +01:00
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil)
|
2021-03-01 01:47:30 +01:00
|
|
|
} else if models.IsErrRepoTransferInProgress(err) {
|
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.settings.transfer_in_progress"), tplSettingsOptions, nil)
|
2014-09-13 00:29:58 +02:00
|
|
|
} else {
|
2018-01-10 22:34:17 +01:00
|
|
|
ctx.ServerError("TransferOwnership", err)
|
2014-09-13 00:29:58 +02:00
|
|
|
}
|
2021-03-01 01:47:30 +01:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Trace("Repository transfer process was started: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner)
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.transfer_started", newOwner.DisplayName()))
|
2021-11-16 19:18:25 +01:00
|
|
|
ctx.Redirect(repo.Link() + "/settings")
|
2021-03-01 01:47:30 +01:00
|
|
|
|
|
|
|
case "cancel_transfer":
|
|
|
|
if !ctx.Repo.IsOwner() {
|
2021-04-05 17:30:52 +02:00
|
|
|
ctx.Error(http.StatusNotFound)
|
2021-03-01 01:47:30 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-12-10 03:46:31 +01:00
|
|
|
repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
|
2021-03-01 01:47:30 +01:00
|
|
|
if err != nil {
|
|
|
|
if models.IsErrNoPendingTransfer(err) {
|
|
|
|
ctx.Flash.Error("repo.settings.transfer_abort_invalid")
|
2021-11-16 19:18:25 +01:00
|
|
|
ctx.Redirect(repo.Link() + "/settings")
|
2021-03-01 01:47:30 +01:00
|
|
|
} else {
|
|
|
|
ctx.ServerError("GetPendingRepositoryTransfer", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-12-10 03:46:31 +01:00
|
|
|
if err := repoTransfer.LoadAttributes(ctx); err != nil {
|
2021-03-01 01:47:30 +01:00
|
|
|
ctx.ServerError("LoadRecipient", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-02-05 07:17:23 +01:00
|
|
|
if err := repo_service.CancelRepositoryTransfer(ctx, ctx.Repo.Repository); err != nil {
|
2021-03-01 01:47:30 +01:00
|
|
|
ctx.ServerError("CancelRepositoryTransfer", err)
|
2014-07-26 08:28:04 +02:00
|
|
|
return
|
|
|
|
}
|
2019-02-28 04:51:46 +01:00
|
|
|
|
2021-03-01 01:47:30 +01:00
|
|
|
log.Trace("Repository transfer process was cancelled: %s/%s ", ctx.Repo.Owner.Name, repo.Name)
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.transfer_abort_success", repoTransfer.Recipient.Name))
|
2021-11-16 19:18:25 +01:00
|
|
|
ctx.Redirect(repo.Link() + "/settings")
|
2016-03-06 02:45:23 +01:00
|
|
|
|
2014-07-26 08:28:04 +02:00
|
|
|
case "delete":
|
2016-03-06 02:45:23 +01:00
|
|
|
if !ctx.Repo.IsOwner() {
|
2021-04-05 17:30:52 +02:00
|
|
|
ctx.Error(http.StatusNotFound)
|
2016-03-06 02:45:23 +01:00
|
|
|
return
|
|
|
|
}
|
2023-11-23 20:24:52 +01:00
|
|
|
if repo.FullName() != form.RepoName {
|
2016-11-07 21:58:22 +01:00
|
|
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
2014-07-26 08:28:04 +02:00
|
|
|
return
|
2014-08-27 10:39:36 +02:00
|
|
|
}
|
|
|
|
|
2021-05-14 22:19:38 +02:00
|
|
|
// Close the gitrepository before doing this.
|
|
|
|
if ctx.Repo.GitRepo != nil {
|
|
|
|
ctx.Repo.GitRepo.Close()
|
|
|
|
}
|
|
|
|
|
2022-03-22 08:03:22 +01:00
|
|
|
if err := repo_service.DeleteRepository(ctx, ctx.Doer, ctx.Repo.Repository, true); err != nil {
|
2018-01-10 22:34:17 +01:00
|
|
|
ctx.ServerError("DeleteRepository", err)
|
2014-07-26 08:28:04 +02:00
|
|
|
return
|
|
|
|
}
|
2015-08-31 07:36:31 +02:00
|
|
|
log.Trace("Repository deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
2015-12-05 23:39:29 +01:00
|
|
|
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.deletion_success"))
|
2015-08-31 07:36:31 +02:00
|
|
|
ctx.Redirect(ctx.Repo.Owner.DashboardLink())
|
2016-03-06 02:45:23 +01:00
|
|
|
|
2016-03-03 21:38:25 +01:00
|
|
|
case "delete-wiki":
|
2016-03-06 02:45:23 +01:00
|
|
|
if !ctx.Repo.IsOwner() {
|
2021-04-05 17:30:52 +02:00
|
|
|
ctx.Error(http.StatusNotFound)
|
2016-03-06 02:45:23 +01:00
|
|
|
return
|
|
|
|
}
|
2023-11-23 20:24:52 +01:00
|
|
|
if repo.FullName() != form.RepoName {
|
2016-11-07 21:58:22 +01:00
|
|
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
2016-03-03 21:38:25 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-20 00:26:57 +01:00
|
|
|
err := wiki_service.DeleteWiki(ctx, repo)
|
2019-06-12 21:41:28 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Error("Delete Wiki: %v", err.Error())
|
|
|
|
}
|
2016-03-03 21:38:25 +01:00
|
|
|
log.Trace("Repository wiki deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
|
|
|
|
2016-03-04 05:24:22 +01:00
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.wiki_deletion_success"))
|
2016-03-03 21:38:25 +01:00
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
2016-08-31 01:18:33 +02:00
|
|
|
|
[GITEA] Allow changing the repo Wiki branch to main
Previously, the repo wiki was hardcoded to use `master` as its branch,
this change makes it possible to use `main` (or something else, governed
by `[repository].DEFAULT_BRANCH`, a setting that already exists and
defaults to `main`).
The way it is done is that a new column is added to the `repository`
table: `wiki_branch`. The migration will make existing repositories
default to `master`, for compatibility's sake, even if they don't have a
Wiki (because it's easier to do that). Newly created repositories will
default to `[repository].DEFAULT_BRANCH` instead.
The Wiki service was updated to use the branch name stored in the
database, and fall back to the default if it is empty.
Old repositories with Wikis using the older `master` branch will have
the option to do a one-time transition to `main`, available via the
repository settings in the "Danger Zone". This option will only be
available for repositories that have the internal wiki enabled, it is
not empty, and the wiki branch is not `[repository].DEFAULT_BRANCH`.
When migrating a repository with a Wiki, Forgejo will use the same
branch name for the wiki as the source repository did. If that's not the
same as the default, the option to normalize it will be available after
the migration's done.
Additionally, the `/api/v1/{owner}/{repo}` endpoint was updated: it will
now include the wiki branch name in `GET` requests, and allow changing
the wiki branch via `PATCH`.
Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu>
(cherry picked from commit d87c526d2a313fa45093ab49b78bb30322b33298)
2024-01-30 12:18:53 +01:00
|
|
|
case "rename-wiki-branch":
|
|
|
|
if !ctx.Repo.IsOwner() {
|
|
|
|
ctx.Error(http.StatusNotFound)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if repo.FullName() != form.RepoName {
|
|
|
|
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := wiki_service.NormalizeWikiBranch(ctx, repo, setting.Repository.DefaultBranch); err != nil {
|
|
|
|
log.Error("Normalize Wiki branch: %v", err.Error())
|
|
|
|
ctx.Flash.Error(ctx.Tr("repo.settings.wiki_branch_rename_failure"))
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
log.Trace("Repository wiki normalized: %s#%s", repo.FullName(), setting.Repository.DefaultBranch)
|
|
|
|
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.wiki_branch_rename_success"))
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
|
|
|
2019-01-23 19:58:38 +01:00
|
|
|
case "archive":
|
|
|
|
if !ctx.Repo.IsOwner() {
|
2021-04-05 17:30:52 +02:00
|
|
|
ctx.Error(http.StatusForbidden)
|
2019-01-23 19:58:38 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if repo.IsMirror {
|
|
|
|
ctx.Flash.Error(ctx.Tr("repo.settings.archive.error_ismirror"))
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-09-16 16:39:12 +02:00
|
|
|
if err := repo_model.SetArchiveRepoState(ctx, repo, true); err != nil {
|
2019-04-02 09:48:31 +02:00
|
|
|
log.Error("Tried to archive a repo: %s", err)
|
2019-01-23 19:58:38 +01:00
|
|
|
ctx.Flash.Error(ctx.Tr("repo.settings.archive.error"))
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.archive.success"))
|
|
|
|
|
|
|
|
log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
2021-09-07 17:49:36 +02:00
|
|
|
|
2019-01-23 19:58:38 +01:00
|
|
|
case "unarchive":
|
|
|
|
if !ctx.Repo.IsOwner() {
|
2021-04-05 17:30:52 +02:00
|
|
|
ctx.Error(http.StatusForbidden)
|
2019-01-23 19:58:38 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-09-16 16:39:12 +02:00
|
|
|
if err := repo_model.SetArchiveRepoState(ctx, repo, false); err != nil {
|
2019-04-02 09:48:31 +02:00
|
|
|
log.Error("Tried to unarchive a repo: %s", err)
|
2019-01-23 19:58:38 +01:00
|
|
|
ctx.Flash.Error(ctx.Tr("repo.settings.unarchive.error"))
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.unarchive.success"))
|
|
|
|
|
|
|
|
log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
|
|
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
|
|
|
|
2016-08-31 01:18:33 +02:00
|
|
|
default:
|
2018-01-10 22:34:17 +01:00
|
|
|
ctx.NotFound("", nil)
|
2014-07-26 08:28:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-09 00:25:57 +02:00
|
|
|
func handleSettingRemoteAddrError(ctx *context.Context, err error, form *forms.RepoSettingForm) {
|
|
|
|
if models.IsErrInvalidCloneAddr(err) {
|
|
|
|
addrErr := err.(*models.ErrInvalidCloneAddr)
|
|
|
|
switch {
|
|
|
|
case addrErr.IsProtocolInvalid:
|
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.mirror_address_protocol_invalid"), tplSettingsOptions, form)
|
|
|
|
case addrErr.IsURLError:
|
2022-06-12 07:43:27 +02:00
|
|
|
ctx.RenderWithErr(ctx.Tr("form.url_error", addrErr.Host), tplSettingsOptions, form)
|
2021-04-09 00:25:57 +02:00
|
|
|
case addrErr.IsPermissionDenied:
|
|
|
|
if addrErr.LocalPath {
|
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), tplSettingsOptions, form)
|
|
|
|
} else {
|
2021-11-20 10:34:05 +01:00
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied_blocked"), tplSettingsOptions, form)
|
2021-04-09 00:25:57 +02:00
|
|
|
}
|
|
|
|
case addrErr.IsInvalidPath:
|
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), tplSettingsOptions, form)
|
|
|
|
default:
|
|
|
|
ctx.ServerError("Unknown error", err)
|
|
|
|
}
|
2021-08-24 00:09:25 +02:00
|
|
|
return
|
2021-04-09 00:25:57 +02:00
|
|
|
}
|
|
|
|
ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, form)
|
|
|
|
}
|
|
|
|
|
2022-07-30 18:45:59 +02:00
|
|
|
func selectPushMirrorByForm(ctx *context.Context, form *forms.RepoSettingForm, repo *repo_model.Repository) (*repo_model.PushMirror, error) {
|
2021-06-14 19:20:43 +02:00
|
|
|
id, err := strconv.ParseInt(form.PushMirrorID, 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-07-30 18:45:59 +02:00
|
|
|
pushMirrors, _, err := repo_model.GetPushMirrorsByRepoID(ctx, repo.ID, db.ListOptions{})
|
2021-12-10 02:27:50 +01:00
|
|
|
if err != nil {
|
2021-06-14 19:20:43 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-12-10 02:27:50 +01:00
|
|
|
for _, m := range pushMirrors {
|
2021-06-14 19:20:43 +02:00
|
|
|
if m.ID == id {
|
2022-05-20 16:08:52 +02:00
|
|
|
m.Repo = repo
|
2021-06-14 19:20:43 +02:00
|
|
|
return m, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("PushMirror[%v] not associated to repository %v", id, repo)
|
|
|
|
}
|