-
-
Notifications
You must be signed in to change notification settings - Fork 6.2k
Introduce "config edit-ini" sub command to help maintaining INI config file #35735
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+260
−175
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
63a5301
fix
wxiaoguang c6d1837
fix abused TempDir
wxiaoguang 6802be3
refactor: "edit-ini --in-place --config-keep-keys ..."
wxiaoguang 3fc0346
fine tune and fix lint
wxiaoguang f21a0f8
fine tune
wxiaoguang 70f1c8f
fine tune
wxiaoguang 614648e
fix lint
wxiaoguang 158acfa
Merge branch 'main' into fix-env-ini
GiteaBot 37e9a0a
fine tune (update comment, rename func)
wxiaoguang File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,20 +26,16 @@ WORKDIR ${GOPATH}/src/code.gitea.io/gitea | |
| RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \ | ||
| && make clean-all build | ||
|
|
||
| # Begin env-to-ini build | ||
| RUN go build contrib/environment-to-ini/environment-to-ini.go | ||
|
|
||
| # Copy local files | ||
| COPY docker/root /tmp/local | ||
|
|
||
| # Set permissions | ||
| RUN chmod 755 /tmp/local/usr/bin/entrypoint \ | ||
| /tmp/local/usr/local/bin/gitea \ | ||
| /tmp/local/usr/local/bin/* \ | ||
| /tmp/local/etc/s6/gitea/* \ | ||
| /tmp/local/etc/s6/openssh/* \ | ||
| /tmp/local/etc/s6/.s6-svscan/* \ | ||
| /go/src/code.gitea.io/gitea/gitea \ | ||
| /go/src/code.gitea.io/gitea/environment-to-ini | ||
| /go/src/code.gitea.io/gitea/gitea | ||
|
|
||
| FROM docker.io/library/alpine:3.22 | ||
| LABEL maintainer="[email protected]" | ||
|
|
@@ -82,4 +78,3 @@ CMD ["/usr/bin/s6-svscan", "/etc/s6"] | |
|
|
||
| COPY --from=build-env /tmp/local / | ||
| COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea | ||
| COPY --from=build-env /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,18 +26,12 @@ WORKDIR ${GOPATH}/src/code.gitea.io/gitea | |
| RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \ | ||
| && make clean-all build | ||
|
|
||
| # Begin env-to-ini build | ||
| RUN go build contrib/environment-to-ini/environment-to-ini.go | ||
|
|
||
| # Copy local files | ||
| COPY docker/rootless /tmp/local | ||
|
|
||
| # Set permissions | ||
| RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \ | ||
| /tmp/local/usr/local/bin/docker-setup.sh \ | ||
| /tmp/local/usr/local/bin/gitea \ | ||
| /go/src/code.gitea.io/gitea/gitea \ | ||
| /go/src/code.gitea.io/gitea/environment-to-ini | ||
| RUN chmod 755 /tmp/local/usr/local/bin/* \ | ||
| /go/src/code.gitea.io/gitea/gitea | ||
|
|
||
| FROM docker.io/library/alpine:3.22 | ||
| LABEL maintainer="[email protected]" | ||
|
|
@@ -71,7 +65,6 @@ RUN chown git:git /var/lib/gitea /etc/gitea | |
|
|
||
| COPY --from=build-env /tmp/local / | ||
| COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea | ||
| COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini | ||
|
|
||
| # git:git | ||
| USER 1000:1000 | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,156 @@ | ||
| // Copyright 2025 The Gitea Authors. All rights reserved. | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| package cmd | ||
|
|
||
| import ( | ||
| "context" | ||
| "errors" | ||
| "fmt" | ||
| "os" | ||
|
|
||
| "code.gitea.io/gitea/modules/setting" | ||
|
|
||
| "github.com/urfave/cli/v3" | ||
| ) | ||
|
|
||
| func cmdConfig() *cli.Command { | ||
| subcmdConfigEditIni := &cli.Command{ | ||
| Name: "edit-ini", | ||
| Usage: "Load an existing INI file, apply environment variables, keep specified keys, and output to a new INI file.", | ||
| Description: ` | ||
| Help users to edit the Gitea configuration INI file. | ||
|
|
||
| # Keep Specified Keys | ||
|
|
||
| If you need to re-create the configuration file with only a subset of keys, | ||
| you can provide an INI template file for the kept keys and use the "--config-keep-keys" flag. | ||
| For example, if a helm chart needs to reset the settings and only keep SECRET_KEY, | ||
| it can use a template file (only keys take effect, values are ignored): | ||
|
|
||
| [security] | ||
| SECRET_KEY= | ||
|
|
||
| $ ./gitea config edit-ini --config app-old.ini --config-keep-keys app-keys.ini --out app-new.ini | ||
|
|
||
| # Map Environment Variables to INI Configuration | ||
|
|
||
| Environment variables of the form "GITEA__section_name__KEY_NAME" | ||
| will be mapped to the ini section "[section_name]" and the key | ||
| "KEY_NAME" with the value as provided. | ||
|
|
||
| Environment variables of the form "GITEA__section_name__KEY_NAME__FILE" | ||
| will be mapped to the ini section "[section_name]" and the key | ||
| "KEY_NAME" with the value loaded from the specified file. | ||
|
|
||
| Environment variable keys can only contain characters "0-9A-Z_", | ||
| if a section or key name contains dot ".", it needs to be escaped as _0x2E_. | ||
| For example, to apply this config: | ||
|
|
||
| [git.config] | ||
| foo.bar=val | ||
|
|
||
| $ export GITEA__git_0x2E_config__foo_0x2E_bar=val | ||
|
|
||
| # Put All Together | ||
|
|
||
| $ ./gitea config edit-ini --config app.ini --config-keep-keys app-keys.ini --apply-env {--in-place|--out app-new.ini} | ||
| `, | ||
| Flags: []cli.Flag{ | ||
| // "--config" flag is provided by global flags, and this flag is also used by "environment-to-ini" script wrapper | ||
| // "--in-place" is also used by "environment-to-ini" script wrapper for its old behavior: always overwrite the existing config file | ||
| &cli.BoolFlag{ | ||
| Name: "in-place", | ||
| Usage: "Output to the same config file as input. This flag will be ignored if --out is set.", | ||
| }, | ||
| &cli.StringFlag{ | ||
| Name: "config-keep-keys", | ||
| Usage: "An INI template file containing keys for keeping. Only the keys defined in the INI template will be kept from old config. If not set, all keys will be kept.", | ||
| }, | ||
| &cli.BoolFlag{ | ||
| Name: "apply-env", | ||
| Usage: "Apply all GITEA__* variables from the environment to the config.", | ||
| }, | ||
| &cli.StringFlag{ | ||
| Name: "out", | ||
wxiaoguang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Usage: "Destination config file to write to.", | ||
| }, | ||
| }, | ||
| Action: runConfigEditIni, | ||
| } | ||
|
|
||
| return &cli.Command{ | ||
| Name: "config", | ||
| Usage: "Manage Gitea configuration", | ||
| Commands: []*cli.Command{ | ||
| subcmdConfigEditIni, | ||
| }, | ||
| } | ||
| } | ||
|
|
||
| func runConfigEditIni(_ context.Context, c *cli.Command) error { | ||
| // the config system may change the environment variables, so get a copy first, to be used later | ||
| env := append([]string{}, os.Environ()...) | ||
|
|
||
| // don't use the guessed setting.CustomConf, instead, require the user to provide --config explicitly | ||
| if !c.IsSet("config") { | ||
| return errors.New("flag is required but not set: --config") | ||
| } | ||
| configFileIn := c.String("config") | ||
|
|
||
| cfgIn, err := setting.NewConfigProviderFromFile(configFileIn) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to load config file %q: %v", configFileIn, err) | ||
| } | ||
|
|
||
| // determine output config file: use "--out" flag or use "--in-place" flag to overwrite input file | ||
| inPlace := c.Bool("in-place") | ||
| configFileOut := c.String("out") | ||
| if configFileOut == "" { | ||
| if !inPlace { | ||
| return errors.New("either --in-place or --out must be specified") | ||
| } | ||
| configFileOut = configFileIn // in-place edit | ||
| } | ||
|
|
||
| needWriteOut := configFileOut != configFileIn | ||
|
|
||
| cfgOut := cfgIn | ||
| configKeepKeys := c.String("config-keep-keys") | ||
| if configKeepKeys != "" { | ||
| needWriteOut = true | ||
| cfgOut, err = setting.NewConfigProviderFromFile(configKeepKeys) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to load config-keep-keys template file %q: %v", configKeepKeys, err) | ||
| } | ||
|
|
||
| for _, secOut := range cfgOut.Sections() { | ||
| for _, keyOut := range secOut.Keys() { | ||
| secIn := cfgIn.Section(secOut.Name()) | ||
| keyIn := setting.ConfigSectionKey(secIn, keyOut.Name()) | ||
| if keyIn != nil { | ||
| keyOut.SetValue(keyIn.String()) | ||
| } else { | ||
| secOut.DeleteKey(keyOut.Name()) | ||
| } | ||
| } | ||
| if len(secOut.Keys()) == 0 { | ||
| cfgOut.DeleteSection(secOut.Name()) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if c.Bool("apply-env") { | ||
| if setting.EnvironmentToConfig(cfgOut, env) { | ||
| needWriteOut = true | ||
| } | ||
| } | ||
|
|
||
| if needWriteOut { | ||
| err = cfgOut.SaveTo(configFileOut) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| // Copyright 2025 The Gitea Authors. All rights reserved. | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| package cmd | ||
|
|
||
| import ( | ||
| "os" | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestConfigEdit(t *testing.T) { | ||
| tmpDir := t.TempDir() | ||
| configOld := tmpDir + "/app-old.ini" | ||
| configTemplate := tmpDir + "/app-template.ini" | ||
| _ = os.WriteFile(configOld, []byte(` | ||
| [sec] | ||
| k1=v1 | ||
| k2=v2 | ||
| `), os.ModePerm) | ||
|
|
||
| _ = os.WriteFile(configTemplate, []byte(` | ||
| [sec] | ||
| k1=in-template | ||
|
|
||
| [sec2] | ||
| k3=v3 | ||
| `), os.ModePerm) | ||
|
|
||
| t.Setenv("GITEA__EnV__KeY", "val") | ||
|
|
||
| t.Run("OutputToNewWithEnv", func(t *testing.T) { | ||
| configNew := tmpDir + "/app-new.ini" | ||
| err := NewMainApp(AppVersion{}).Run(t.Context(), []string{ | ||
| "./gitea", "--config", configOld, | ||
| "config", "edit-ini", | ||
| "--apply-env", | ||
| "--config-keep-keys", configTemplate, | ||
| "--out", configNew, | ||
| }) | ||
| require.NoError(t, err) | ||
|
|
||
| // "k1" old value is kept because its key is in the template | ||
| // "k2" is removed because it isn't in the template | ||
| // "k3" isn't in new config because it isn't in the old config | ||
| // [env] is applied from environment variable | ||
| data, _ := os.ReadFile(configNew) | ||
| require.Equal(t, `[sec] | ||
| k1 = v1 | ||
|
|
||
| [env] | ||
| KeY = val | ||
| `, string(data)) | ||
| }) | ||
|
|
||
| t.Run("OutputToExisting(environment-to-ini)", func(t *testing.T) { | ||
wxiaoguang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // the legacy "environment-to-ini" (now a wrapper script) behavior: | ||
| // if no "--out", then "--in-place" must be used to overwrite the existing "--config" file | ||
| err := NewMainApp(AppVersion{}).Run(t.Context(), []string{ | ||
| "./gitea", "config", "edit-ini", | ||
| "--apply-env", | ||
| "--config", configOld, | ||
| }) | ||
| require.ErrorContains(t, err, "either --in-place or --out must be specified") | ||
|
|
||
| // simulate the "environment-to-ini" behavior with "--in-place" | ||
| err = NewMainApp(AppVersion{}).Run(t.Context(), []string{ | ||
| "./gitea", "config", "edit-ini", | ||
| "--in-place", | ||
| "--apply-env", | ||
| "--config", configOld, | ||
| }) | ||
| require.NoError(t, err) | ||
|
|
||
| data, _ := os.ReadFile(configOld) | ||
| require.Equal(t, `[sec] | ||
| k1 = v1 | ||
| k2 = v2 | ||
|
|
||
| [env] | ||
| KeY = val | ||
| `, string(data)) | ||
| }) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.