mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-31 14:31:02 +00:00 
			
		
		
		
	- When specifying push options, tooling like [git-repo-go](https://github.com/alibaba/git-repo-go) encodes pushoption values if they contain newlines or non-ASCII characters as they cannot be easily specified via the CLI otherwise. - Recognize such base64 encoded values in the pushoptions (those that have the `{base64}` prefix), if the base64 decoding fails we return the original value. - Resolves forgejo/forgejo#8161 <!--start release-notes-assistant--> ## Release notes <!--URL:https://codeberg.org/forgejo/forgejo--> - Features - [PR](https://codeberg.org/forgejo/forgejo/pulls/8479): <!--number 8479 --><!--line 0 --><!--description QUdpdCBwdXNoIG9wdGlvbnMgc3RhcnRpbmcgd2l0aCBge2Jhc2U2NH1gIGFyZSBkZWNvZGVk-->AGit push options starting with `{base64}` are decoded<!--description--> <!--end release-notes-assistant--> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8479 Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org> Co-authored-by: Gusted <postmaster@gusted.xyz> Co-committed-by: Gusted <postmaster@gusted.xyz>
		
			
				
	
	
		
			131 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			131 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright twenty-panda <twenty-panda@posteo.com>
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package pushoptions
 | |
| 
 | |
| import (
 | |
| 	"encoding/base64"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| type Key string
 | |
| 
 | |
| const (
 | |
| 	RepoPrivate     = Key("repo.private")
 | |
| 	RepoTemplate    = Key("repo.template")
 | |
| 	AgitTopic       = Key("topic")
 | |
| 	AgitForcePush   = Key("force-push")
 | |
| 	AgitTitle       = Key("title")
 | |
| 	AgitDescription = Key("description")
 | |
| 
 | |
| 	envPrefix = "GIT_PUSH_OPTION"
 | |
| 	EnvCount  = envPrefix + "_COUNT"
 | |
| 	EnvFormat = envPrefix + "_%d"
 | |
| )
 | |
| 
 | |
| type Interface interface {
 | |
| 	ReadEnv() Interface
 | |
| 	Parse(string) bool
 | |
| 	Map() map[string]string
 | |
| 
 | |
| 	ChangeRepoSettings() bool
 | |
| 
 | |
| 	Empty() bool
 | |
| 
 | |
| 	GetBool(key Key, def bool) bool
 | |
| 	GetString(key Key) (val string, ok bool)
 | |
| }
 | |
| 
 | |
| type gitPushOptions map[string]string
 | |
| 
 | |
| func New() Interface {
 | |
| 	pushOptions := gitPushOptions(make(map[string]string))
 | |
| 	return &pushOptions
 | |
| }
 | |
| 
 | |
| func NewFromMap(o *map[string]string) Interface {
 | |
| 	return (*gitPushOptions)(o)
 | |
| }
 | |
| 
 | |
| func (o *gitPushOptions) ReadEnv() Interface {
 | |
| 	if pushCount, err := strconv.Atoi(os.Getenv(EnvCount)); err == nil {
 | |
| 		for idx := 0; idx < pushCount; idx++ {
 | |
| 			_ = o.Parse(os.Getenv(fmt.Sprintf(EnvFormat, idx)))
 | |
| 		}
 | |
| 	}
 | |
| 	return o
 | |
| }
 | |
| 
 | |
| func (o *gitPushOptions) Parse(data string) bool {
 | |
| 	key, value, found := strings.Cut(data, "=")
 | |
| 	if !found {
 | |
| 		value = "true"
 | |
| 	}
 | |
| 	switch Key(key) {
 | |
| 	case RepoPrivate:
 | |
| 	case RepoTemplate:
 | |
| 	case AgitTopic:
 | |
| 	case AgitForcePush:
 | |
| 	case AgitTitle:
 | |
| 	case AgitDescription:
 | |
| 	default:
 | |
| 		return false
 | |
| 	}
 | |
| 	(*o)[key] = value
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| func (o gitPushOptions) Map() map[string]string {
 | |
| 	return o
 | |
| }
 | |
| 
 | |
| func (o gitPushOptions) ChangeRepoSettings() bool {
 | |
| 	if o.Empty() {
 | |
| 		return false
 | |
| 	}
 | |
| 	for _, key := range []Key{RepoPrivate, RepoTemplate} {
 | |
| 		_, ok := o[string(key)]
 | |
| 		if ok {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func (o gitPushOptions) Empty() bool {
 | |
| 	return len(o) == 0
 | |
| }
 | |
| 
 | |
| func (o gitPushOptions) GetBool(key Key, def bool) bool {
 | |
| 	if val, ok := o[string(key)]; ok {
 | |
| 		if b, err := strconv.ParseBool(val); err == nil {
 | |
| 			return b
 | |
| 		}
 | |
| 	}
 | |
| 	return def
 | |
| }
 | |
| 
 | |
| func (o gitPushOptions) GetString(key Key) (string, bool) {
 | |
| 	val, ok := o[string(key)]
 | |
| 	if !ok {
 | |
| 		return "", false
 | |
| 	}
 | |
| 
 | |
| 	// If the value is prefixed with `{base64}` then everything after that is very
 | |
| 	// likely to be encoded via base64.
 | |
| 	base64Value, found := strings.CutPrefix(val, "{base64}")
 | |
| 	if !found {
 | |
| 		return val, true
 | |
| 	}
 | |
| 
 | |
| 	value, err := base64.StdEncoding.DecodeString(base64Value)
 | |
| 	if err != nil {
 | |
| 		// Not valid base64? Return the original value.
 | |
| 		return val, true
 | |
| 	}
 | |
| 
 | |
| 	return string(value), true
 | |
| }
 |