[BRANDING] parse FORGEJO__* in the container environment
Add the FORGEJO__ prefix as equivalent to GITEA__ when interpreted by environment-to-ini. It is used when running the Forgejo container like so: docker run --name forgejo -e FORGEJO__security__INSTALL_LOCK=true \ -d codeberg.org/forgejo/forgejo:1.19 (cherry picked from commit6cd61e2ab7
) (cherry picked from commit62cae8cc6a
) (cherry picked from commitaee1afc509
) (cherry picked from commit6ba563cd9b
) (cherry picked from commit6429b20f4a
) (cherry picked from commitdd545aa077
) (cherry picked from commit63a00e573e
) (cherry picked from commit8e35a50b91
) (cherry picked from commit26e8fb6cd9
) (cherry picked from commit56bbf644be
) (cherry picked from commit4d0a8c8640
) (cherry picked from commitb58f775fa2
) (cherry picked from commitf4b6fa7a93
) (cherry picked from commit4eca363082
) (cherry picked from commite2e7a72f80
) (cherry picked from commit00ce992957
) (cherry picked from commit971b26ec1c
) (cherry picked from commit4998a3c39c
) (cherry picked from commit6589275158
)
This commit is contained in:
parent
c1d19c1836
commit
5eadc6df27
5 changed files with 67 additions and 24 deletions
|
@ -50,6 +50,7 @@ jobs:
|
||||||
env:
|
env:
|
||||||
TAGS: bindata
|
TAGS: bindata
|
||||||
- run: |
|
- run: |
|
||||||
|
su gitea -c 'go test contrib/environment-to-ini/environment-to-ini.go contrib/environment-to-ini/environment-to-ini_test.go'
|
||||||
su gitea -c 'make unit-test-coverage test-check'
|
su gitea -c 'make unit-test-coverage test-check'
|
||||||
timeout-minutes: 50
|
timeout-minutes: 50
|
||||||
env:
|
env:
|
||||||
|
|
|
@ -5,6 +5,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -14,21 +15,21 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// EnvironmentPrefix environment variables prefixed with this represent ini values to write
|
// EnvironmentPrefix environment variables prefixed with this represent ini values to write
|
||||||
const EnvironmentPrefix = "GITEA"
|
const EnvironmentPrefix = "^(FORGEJO|GITEA)"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Name = "environment-to-ini"
|
app.Name = "environment-to-ini"
|
||||||
app.Usage = "Use provided environment to update configuration ini"
|
app.Usage = "Use provided environment to update configuration ini"
|
||||||
app.Description = `As a helper to allow docker users to update the gitea configuration
|
app.Description = `As a helper to allow docker users to update the Forgejo configuration
|
||||||
through the environment, this command allows environment variables to
|
through the environment, this command allows environment variables to
|
||||||
be mapped to values in the ini.
|
be mapped to values in the ini.
|
||||||
|
|
||||||
Environment variables of the form "GITEA__SECTION_NAME__KEY_NAME"
|
Environment variables of the form "FORGEJO__SECTION_NAME__KEY_NAME"
|
||||||
will be mapped to the ini section "[section_name]" and the key
|
will be mapped to the ini section "[section_name]" and the key
|
||||||
"KEY_NAME" with the value as provided.
|
"KEY_NAME" with the value as provided.
|
||||||
|
|
||||||
Environment variables of the form "GITEA__SECTION_NAME__KEY_NAME__FILE"
|
Environment variables of the form "FORGEJO__SECTION_NAME__KEY_NAME__FILE"
|
||||||
will be mapped to the ini section "[section_name]" and the key
|
will be mapped to the ini section "[section_name]" and the key
|
||||||
"KEY_NAME" with the value loaded from the specified file.
|
"KEY_NAME" with the value loaded from the specified file.
|
||||||
|
|
||||||
|
@ -46,8 +47,8 @@ func main() {
|
||||||
...
|
...
|
||||||
"""
|
"""
|
||||||
|
|
||||||
You would set the environment variables: "GITEA__LOG_0x2E_CONSOLE__COLORIZE=false"
|
You would set the environment variables: "FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false"
|
||||||
and "GITEA__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found
|
and "FORGEJO__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found
|
||||||
on the configuration cheat sheet.`
|
on the configuration cheat sheet.`
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
|
@ -63,7 +64,7 @@ func main() {
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "work-path, w",
|
Name: "work-path, w",
|
||||||
Value: setting.AppWorkPath,
|
Value: setting.AppWorkPath,
|
||||||
Usage: "Set the gitea working path",
|
Usage: "Set the forgejo working path",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "out, o",
|
Name: "out, o",
|
||||||
|
@ -87,6 +88,19 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func splitEnvironmentVariable(prefixRegexp *regexp.Regexp, kv string) (string, string) {
|
||||||
|
idx := strings.IndexByte(kv, '=')
|
||||||
|
if idx < 0 {
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
k := kv[:idx]
|
||||||
|
loc := prefixRegexp.FindStringIndex(k)
|
||||||
|
if loc == nil {
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
return k[loc[1]:], kv[idx+1:]
|
||||||
|
}
|
||||||
|
|
||||||
func runEnvironmentToIni(c *cli.Context) error {
|
func runEnvironmentToIni(c *cli.Context) error {
|
||||||
setting.InitWorkPathAndCommonConfig(os.Getenv, setting.ArgWorkPathAndCustomConf{
|
setting.InitWorkPathAndCommonConfig(os.Getenv, setting.ArgWorkPathAndCustomConf{
|
||||||
WorkPath: c.String("work-path"),
|
WorkPath: c.String("work-path"),
|
||||||
|
@ -118,17 +132,15 @@ func runEnvironmentToIni(c *cli.Context) error {
|
||||||
|
|
||||||
// clear Gitea's specific environment variables if requested
|
// clear Gitea's specific environment variables if requested
|
||||||
if c.Bool("clear") {
|
if c.Bool("clear") {
|
||||||
|
prefixRegexp := regexp.MustCompile(prefixGitea)
|
||||||
for _, kv := range os.Environ() {
|
for _, kv := range os.Environ() {
|
||||||
idx := strings.IndexByte(kv, '=')
|
eKey, _ := splitEnvironmentVariable(prefixRegexp, kv)
|
||||||
if idx < 0 {
|
if eKey == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
eKey := kv[:idx]
|
|
||||||
if strings.HasPrefix(eKey, prefixGitea) {
|
|
||||||
_ = os.Unsetenv(eKey)
|
_ = os.Unsetenv(eKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
21
contrib/environment-to-ini/environment-to-ini_test.go
Normal file
21
contrib/environment-to-ini/environment-to-ini_test.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2023 The Forgejo Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_splitEnvironmentVariable(t *testing.T) {
|
||||||
|
prefixRegexp := regexp.MustCompile(EnvironmentPrefix + "__")
|
||||||
|
k, v := splitEnvironmentVariable(prefixRegexp, "FORGEJO__KEY=VALUE")
|
||||||
|
assert.Equal(t, k, "KEY")
|
||||||
|
assert.Equal(t, v, "VALUE")
|
||||||
|
k, v = splitEnvironmentVariable(prefixRegexp, "nothing=interesting")
|
||||||
|
assert.Equal(t, k, "")
|
||||||
|
assert.Equal(t, v, "")
|
||||||
|
}
|
|
@ -75,19 +75,21 @@ func decodeEnvSectionKey(encoded string) (ok bool, section, key string) {
|
||||||
|
|
||||||
// decodeEnvironmentKey decode the environment key to section and key
|
// decodeEnvironmentKey decode the environment key to section and key
|
||||||
// The environment key is in the form of GITEA__SECTION__KEY or GITEA__SECTION__KEY__FILE
|
// The environment key is in the form of GITEA__SECTION__KEY or GITEA__SECTION__KEY__FILE
|
||||||
func decodeEnvironmentKey(prefixGitea, suffixFile, envKey string) (ok bool, section, key string, useFileValue bool) {
|
func decodeEnvironmentKey(prefixRegexp *regexp.Regexp, suffixFile, envKey string) (ok bool, section, key string, useFileValue bool) {
|
||||||
if !strings.HasPrefix(envKey, prefixGitea) {
|
|
||||||
return false, "", "", false
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(envKey, suffixFile) {
|
if strings.HasSuffix(envKey, suffixFile) {
|
||||||
useFileValue = true
|
useFileValue = true
|
||||||
envKey = envKey[:len(envKey)-len(suffixFile)]
|
envKey = envKey[:len(envKey)-len(suffixFile)]
|
||||||
}
|
}
|
||||||
ok, section, key = decodeEnvSectionKey(envKey[len(prefixGitea):])
|
loc := prefixRegexp.FindStringIndex(envKey)
|
||||||
|
if loc == nil {
|
||||||
|
return false, "", "", false
|
||||||
|
}
|
||||||
|
ok, section, key = decodeEnvSectionKey(envKey[loc[1]:])
|
||||||
return ok, section, key, useFileValue
|
return ok, section, key, useFileValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func EnvironmentToConfig(cfg ConfigProvider, prefixGitea, suffixFile string, envs []string) (changed bool) {
|
func EnvironmentToConfig(cfg ConfigProvider, prefixGitea, suffixFile string, envs []string) (changed bool) {
|
||||||
|
prefixRegexp := regexp.MustCompile(prefixGitea)
|
||||||
for _, kv := range envs {
|
for _, kv := range envs {
|
||||||
idx := strings.IndexByte(kv, '=')
|
idx := strings.IndexByte(kv, '=')
|
||||||
if idx < 0 {
|
if idx < 0 {
|
||||||
|
@ -97,7 +99,7 @@ func EnvironmentToConfig(cfg ConfigProvider, prefixGitea, suffixFile string, env
|
||||||
// parse the environment variable to config section name and key name
|
// parse the environment variable to config section name and key name
|
||||||
envKey := kv[:idx]
|
envKey := kv[:idx]
|
||||||
envValue := kv[idx+1:]
|
envValue := kv[idx+1:]
|
||||||
ok, sectionName, keyName, useFileValue := decodeEnvironmentKey(prefixGitea, suffixFile, envKey)
|
ok, sectionName, keyName, useFileValue := decodeEnvironmentKey(prefixRegexp, suffixFile, envKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ package setting
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -33,7 +34,7 @@ func TestDecodeEnvSectionKey(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDecodeEnvironmentKey(t *testing.T) {
|
func TestDecodeEnvironmentKey(t *testing.T) {
|
||||||
prefix := "GITEA__"
|
prefix := regexp.MustCompile("^(FORGEJO|GITEA)__")
|
||||||
suffix := "__FILE"
|
suffix := "__FILE"
|
||||||
|
|
||||||
ok, section, key, file := decodeEnvironmentKey(prefix, suffix, "SEC__KEY")
|
ok, section, key, file := decodeEnvironmentKey(prefix, suffix, "SEC__KEY")
|
||||||
|
@ -54,6 +55,12 @@ func TestDecodeEnvironmentKey(t *testing.T) {
|
||||||
assert.Equal(t, "KEY", key)
|
assert.Equal(t, "KEY", key)
|
||||||
assert.False(t, file)
|
assert.False(t, file)
|
||||||
|
|
||||||
|
ok, section, key, file = decodeEnvironmentKey(prefix, suffix, "FORGEJO__SEC__KEY")
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, "sec", section)
|
||||||
|
assert.Equal(t, "KEY", key)
|
||||||
|
assert.False(t, file)
|
||||||
|
|
||||||
// with "__FILE" suffix, it doesn't support to write "[sec].FILE" to config (no such key FILE is used in Gitea)
|
// with "__FILE" suffix, it doesn't support to write "[sec].FILE" to config (no such key FILE is used in Gitea)
|
||||||
// but it could be fixed in the future by adding a new suffix like "__VALUE" (no such key VALUE is used in Gitea either)
|
// but it could be fixed in the future by adding a new suffix like "__VALUE" (no such key VALUE is used in Gitea either)
|
||||||
ok, section, key, file = decodeEnvironmentKey(prefix, suffix, "GITEA__SEC__FILE")
|
ok, section, key, file = decodeEnvironmentKey(prefix, suffix, "GITEA__SEC__FILE")
|
||||||
|
@ -72,7 +79,7 @@ func TestDecodeEnvironmentKey(t *testing.T) {
|
||||||
func TestEnvironmentToConfig(t *testing.T) {
|
func TestEnvironmentToConfig(t *testing.T) {
|
||||||
cfg, _ := NewConfigProviderFromData("")
|
cfg, _ := NewConfigProviderFromData("")
|
||||||
|
|
||||||
changed := EnvironmentToConfig(cfg, "GITEA__", "__FILE", nil)
|
changed := EnvironmentToConfig(cfg, "^(FORGEJO|GITEA)__", "__FILE", nil)
|
||||||
assert.False(t, changed)
|
assert.False(t, changed)
|
||||||
|
|
||||||
cfg, err := NewConfigProviderFromData(`
|
cfg, err := NewConfigProviderFromData(`
|
||||||
|
@ -81,16 +88,16 @@ key = old
|
||||||
`)
|
`)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
changed = EnvironmentToConfig(cfg, "GITEA__", "__FILE", []string{"GITEA__sec__key=new"})
|
changed = EnvironmentToConfig(cfg, "^(FORGEJO|GITEA)__", "__FILE", []string{"GITEA__sec__key=new"})
|
||||||
assert.True(t, changed)
|
assert.True(t, changed)
|
||||||
assert.Equal(t, "new", cfg.Section("sec").Key("key").String())
|
assert.Equal(t, "new", cfg.Section("sec").Key("key").String())
|
||||||
|
|
||||||
changed = EnvironmentToConfig(cfg, "GITEA__", "__FILE", []string{"GITEA__sec__key=new"})
|
changed = EnvironmentToConfig(cfg, "^(FORGEJO|GITEA)__", "__FILE", []string{"GITEA__sec__key=new"})
|
||||||
assert.False(t, changed)
|
assert.False(t, changed)
|
||||||
|
|
||||||
tmpFile := t.TempDir() + "/the-file"
|
tmpFile := t.TempDir() + "/the-file"
|
||||||
_ = os.WriteFile(tmpFile, []byte("value-from-file"), 0o644)
|
_ = os.WriteFile(tmpFile, []byte("value-from-file"), 0o644)
|
||||||
changed = EnvironmentToConfig(cfg, "GITEA__", "__FILE", []string{"GITEA__sec__key__FILE=" + tmpFile})
|
changed = EnvironmentToConfig(cfg, "^(FORGEJO|GITEA)__", "__FILE", []string{"GITEA__sec__key__FILE=" + tmpFile})
|
||||||
assert.True(t, changed)
|
assert.True(t, changed)
|
||||||
assert.Equal(t, "value-from-file", cfg.Section("sec").Key("key").String())
|
assert.Equal(t, "value-from-file", cfg.Section("sec").Key("key").String())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue