Initial support for push options (#12169)
* Initial support for push options Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix misspelling 🤦 Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix formatting after conflict resolution * defer close git repo * According the GitLab documentation, git >= 2.10 Signed-off-by: jolheiser <john.olheiser@gmail.com> * Words are hard. Thanks @mrsdizzie 😅 Co-authored-by: mrsdizzie <info@mrsdizzie.com> * Only update if there are push options Signed-off-by: jolheiser <john.olheiser@gmail.com> Co-authored-by: mrsdizzie <info@mrsdizzie.com>
This commit is contained in:
parent
e7d65cbc6e
commit
43a397ce9a
|
@ -127,6 +127,12 @@ var checklist = []check{
|
||||||
isDefault: false,
|
isDefault: false,
|
||||||
f: runDoctorUserStarNum,
|
f: runDoctorUserStarNum,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Enable push options",
|
||||||
|
name: "enable-push-options",
|
||||||
|
isDefault: false,
|
||||||
|
f: runDoctorEnablePushOptions,
|
||||||
|
},
|
||||||
// more checks please append here
|
// more checks please append here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -605,3 +611,28 @@ func runDoctorCheckDBConsistency(ctx *cli.Context) ([]string, error) {
|
||||||
|
|
||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runDoctorEnablePushOptions(ctx *cli.Context) ([]string, error) {
|
||||||
|
numRepos := 0
|
||||||
|
_, err := iterateRepositories(func(repo *models.Repository) ([]string, error) {
|
||||||
|
numRepos++
|
||||||
|
r, err := git.OpenRepository(repo.RepoPath())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
|
if ctx.Bool("fix") {
|
||||||
|
_, err := git.NewCommand("config", "receive.advertisePushOptions", "true").RunInDir(r.Path)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
var prefix string
|
||||||
|
if !ctx.Bool("fix") {
|
||||||
|
prefix = "DRY RUN: "
|
||||||
|
}
|
||||||
|
return []string{fmt.Sprintf("%sEnabled push options for %d repositories.", prefix, numRepos)}, err
|
||||||
|
}
|
||||||
|
|
16
cmd/hook.go
16
cmd/hook.go
|
@ -178,6 +178,7 @@ Gitea or set your environment appropriately.`, "")
|
||||||
GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
|
GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
|
||||||
GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
|
GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
|
||||||
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
|
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
|
||||||
|
GitPushOptions: pushOptions(),
|
||||||
ProtectedBranchID: prID,
|
ProtectedBranchID: prID,
|
||||||
IsDeployKey: isDeployKey,
|
IsDeployKey: isDeployKey,
|
||||||
}
|
}
|
||||||
|
@ -326,6 +327,7 @@ Gitea or set your environment appropriately.`, "")
|
||||||
GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
|
GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
|
||||||
GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
|
GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
|
||||||
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
|
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
|
||||||
|
GitPushOptions: pushOptions(),
|
||||||
}
|
}
|
||||||
oldCommitIDs := make([]string, hookBatchSize)
|
oldCommitIDs := make([]string, hookBatchSize)
|
||||||
newCommitIDs := make([]string, hookBatchSize)
|
newCommitIDs := make([]string, hookBatchSize)
|
||||||
|
@ -438,3 +440,17 @@ func hookPrintResults(results []private.HookPostReceiveBranchResult) {
|
||||||
os.Stderr.Sync()
|
os.Stderr.Sync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pushOptions() map[string]string {
|
||||||
|
opts := make(map[string]string)
|
||||||
|
if pushCount, err := strconv.Atoi(os.Getenv(private.GitPushOptionCount)); err == nil {
|
||||||
|
for idx := 0; idx < pushCount; idx++ {
|
||||||
|
opt := os.Getenv(fmt.Sprintf("GIT_PUSH_OPTION_%d", idx))
|
||||||
|
kv := strings.SplitN(opt, "=", 2)
|
||||||
|
if len(kv) == 2 {
|
||||||
|
opts[kv[0]] = kv[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return opts
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
date: "2020-07-06T16:00:00+02:00"
|
||||||
|
title: "Usage: Push Options"
|
||||||
|
slug: "push-options"
|
||||||
|
weight: 15
|
||||||
|
toc: true
|
||||||
|
draft: false
|
||||||
|
menu:
|
||||||
|
sidebar:
|
||||||
|
parent: "usage"
|
||||||
|
name: "Push Options"
|
||||||
|
weight: 15
|
||||||
|
identifier: "push-options"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Push Options
|
||||||
|
|
||||||
|
In Gitea `1.13`, support for some [push options](https://git-scm.com/docs/git-push#Documentation/git-push.txt--oltoptiongt)
|
||||||
|
were added.
|
||||||
|
|
||||||
|
|
||||||
|
## Supported Options
|
||||||
|
|
||||||
|
- `repo.private` (true|false) - Change the repository's visibility.
|
||||||
|
This is particularly useful when combined with push-to-create.
|
||||||
|
- `repo.template` (true|false) - Change whether the repository is a template.
|
||||||
|
|
||||||
|
Example of changing a repository's visibility to public:
|
||||||
|
```shell
|
||||||
|
git push -o repo.private=false -u origin master
|
||||||
|
```
|
|
@ -120,6 +120,12 @@ func Init(ctx context.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if version.Compare(gitVersion, "2.10", ">=") {
|
||||||
|
if err := checkAndSetConfig("receive.advertisePushOptions", "true", true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if version.Compare(gitVersion, "2.18", ">=") {
|
if version.Compare(gitVersion, "2.18", ">=") {
|
||||||
if err := checkAndSetConfig("core.commitGraph", "true", true); err != nil {
|
if err := checkAndSetConfig("core.commitGraph", "true", true); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
@ -19,8 +20,28 @@ const (
|
||||||
GitAlternativeObjectDirectories = "GIT_ALTERNATE_OBJECT_DIRECTORIES"
|
GitAlternativeObjectDirectories = "GIT_ALTERNATE_OBJECT_DIRECTORIES"
|
||||||
GitObjectDirectory = "GIT_OBJECT_DIRECTORY"
|
GitObjectDirectory = "GIT_OBJECT_DIRECTORY"
|
||||||
GitQuarantinePath = "GIT_QUARANTINE_PATH"
|
GitQuarantinePath = "GIT_QUARANTINE_PATH"
|
||||||
|
GitPushOptionCount = "GIT_PUSH_OPTION_COUNT"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GitPushOptions is a wrapper around a map[string]string
|
||||||
|
type GitPushOptions map[string]string
|
||||||
|
|
||||||
|
// GitPushOptions keys
|
||||||
|
const (
|
||||||
|
GitPushOptionRepoPrivate = "repo.private"
|
||||||
|
GitPushOptionRepoTemplate = "repo.template"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bool checks for a key in the map and parses as a boolean
|
||||||
|
func (g GitPushOptions) Bool(key string, def bool) bool {
|
||||||
|
if val, ok := g[key]; ok {
|
||||||
|
if b, err := strconv.ParseBool(val); err == nil {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
|
||||||
// HookOptions represents the options for the Hook calls
|
// HookOptions represents the options for the Hook calls
|
||||||
type HookOptions struct {
|
type HookOptions struct {
|
||||||
OldCommitIDs []string
|
OldCommitIDs []string
|
||||||
|
@ -31,6 +52,7 @@ type HookOptions struct {
|
||||||
GitObjectDirectory string
|
GitObjectDirectory string
|
||||||
GitAlternativeObjectDirectories string
|
GitAlternativeObjectDirectories string
|
||||||
GitQuarantinePath string
|
GitQuarantinePath string
|
||||||
|
GitPushOptions GitPushOptions
|
||||||
ProtectedBranchID int64
|
ProtectedBranchID int64
|
||||||
IsDeployKey bool
|
IsDeployKey bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -436,6 +436,18 @@ func HookPostReceive(ctx *macaron.Context, opts private.HookOptions) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Push Options
|
||||||
|
if repo != nil && len(opts.GitPushOptions) > 0 {
|
||||||
|
repo.IsPrivate = opts.GitPushOptions.Bool(private.GitPushOptionRepoPrivate, repo.IsPrivate)
|
||||||
|
repo.IsTemplate = opts.GitPushOptions.Bool(private.GitPushOptionRepoTemplate, repo.IsTemplate)
|
||||||
|
if err := models.UpdateRepositoryCols(repo, "is_private", "is_template"); err != nil {
|
||||||
|
log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err)
|
||||||
|
ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
|
||||||
|
Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
results := make([]private.HookPostReceiveBranchResult, 0, len(opts.OldCommitIDs))
|
results := make([]private.HookPostReceiveBranchResult, 0, len(opts.OldCommitIDs))
|
||||||
|
|
||||||
// We have to reload the repo in case its state is changed above
|
// We have to reload the repo in case its state is changed above
|
||||||
|
|
Loading…
Reference in New Issue