Files
act_runner/internal/app/cmd/config.go
Lunny Xiao 24c13a1fd0 chore: revert 4c2ab943a8 (#1148)
Revert #1136 and use actionslib instead.

revert chore: bump the module path to `/v3`, take the version from the VCS stamp (#1136)

gitea can not consume the runner's api by version while it's version mismatches the module version:

```
go: gitea.com/gitea/runner@v3.0.1: invalid version: module contains a go.mod file,
so module path must match major version ("gitea.com/gitea/runner/v3")
```

Fix that by bumping the module version now. The existing `v3.0.0` and `v3.0.1` tags stay unusable, so a new tag is needed after this lands.

Also drop the version `-X` linker flags, which would otherwise have to repeat the new path in both `Makefile` and `.goreleaser.yaml`, where a stale path makes injection silently no-op. Go has recorded the module version in the build info since 1.24, so `Version()` reads it from there, keeping the variable as an override for builds without a VCS stamp.

That part started as https://gitea.com/gitea/runner/pulls/1137 but belongs here: the stamp resolves against the tags that are legal for the module path, so without the `/v3` bump it would report `v1.0.9-0.<ts>-<sha>`. Since `release-nightly.yml` triggers on every push to `main`, splitting them would publish a nightly with a `v1` version.

---------

Co-authored-by: bircni <bircni@icloud.com>
Reviewed-on: https://gitea.com/gitea/runner/pulls/1136
Reviewed-by: techknowlogick <9+techknowlogick@noreply.gitea.com>
Reviewed-by: bircni <bircni@icloud.com>
Co-authored-by: silverwind <me@silverwind.io>
Reviewed-on: https://gitea.com/gitea/runner/pulls/1148
Reviewed-by: Zettat123 <39446+zettat123@noreply.gitea.com>
2026-08-06 21:50:21 +00:00

146 lines
4.0 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"fmt"
"os"
"path/filepath"
"slices"
"strings"
"gitea.com/gitea/runner/internal/pkg/config"
"github.com/spf13/cobra"
)
func loadConfigCmd(configFile *string) *cobra.Command {
configCmd := &cobra.Command{
Use: "config",
Short: "Generate, read and edit config files",
Args: cobra.MaximumNArgs(0),
RunE: func(cmd *cobra.Command, _ []string) error {
return cmd.Help()
},
}
configCmd.AddCommand(loadGenerateConfigCmd("generate"))
configCmd.AddCommand(loadInitConfigCmd(configFile))
configCmd.AddCommand(&cobra.Command{
Use: "get <key>",
Short: "Print the value of a config key",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
file, err := resolveConfigFile(cmd, configFile)
if err != nil {
return err
}
value, err := config.GetValue(file, args[0])
if err != nil {
return err
}
fmt.Fprintln(cmd.OutOrStdout(), value)
return nil
},
})
for _, sub := range []struct {
use string
short string
edit func(file, key string, values ...string) error
}{
{"set <key> <value>...", "Set the value of a config key", config.SetValue},
{"add <key> <value>...", "Append values to a list config key", config.AddValue},
{"remove <key> <value>...", "Remove values from a list config key", config.RemoveValue},
} {
valueCmd := &cobra.Command{
Use: sub.use,
Short: sub.short,
Args: cobra.MinimumNArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
file, err := resolveConfigFile(cmd, configFile)
if err != nil {
return err
}
return sub.edit(file, args[0], args[1:]...)
},
}
valueCmd.Flags().SetInterspersed(false) // so a value such as `--cpus 2` is not parsed as a flag
configCmd.AddCommand(valueCmd)
}
return configCmd
}
func loadInitConfigCmd(configFile *string) *cobra.Command {
var force bool
initCmd := &cobra.Command{
Use: "init",
Short: "Write a minimal config file",
Long: "Write a minimal config file, leaving every option at its default.\nWithout --config it writes config.yaml in the working directory.",
Args: cobra.MaximumNArgs(0),
RunE: func(cmd *cobra.Command, _ []string) error {
file, taken := *configFile, []string{*configFile}
if file == "" {
file, taken = defaultConfigFileNames[0], defaultConfigFileNames // any of them would shadow the new file
}
for _, name := range taken {
if _, err := os.Stat(name); err == nil && !force {
return fmt.Errorf("config file %q already exists, pass --force to overwrite it", name)
}
}
if err := config.WriteFile(file, []byte(config.Minimal)); err != nil {
return err
}
fmt.Fprintf(cmd.OutOrStdout(), "wrote config file %q\n", file)
return nil
},
}
initCmd.Flags().BoolVarP(&force, "force", "f", false, "overwrite an existing config file")
return initCmd
}
func loadGenerateConfigCmd(use string) *cobra.Command {
return &cobra.Command{
Use: use,
Short: "Print the example config, which documents every option",
Args: cobra.MaximumNArgs(0),
Run: func(cmd *cobra.Command, _ []string) {
fmt.Fprintf(cmd.OutOrStdout(), "%s", config.Example)
},
}
}
var defaultConfigFileNames = []string{"config.yaml", "config.yml"}
func resolveConfigFile(cmd *cobra.Command, configFile *string) (string, error) {
if *configFile != "" {
return *configFile, nil
}
var dirs []string
if wd, err := os.Getwd(); err == nil {
dirs = append(dirs, wd)
}
if exe, err := os.Executable(); err == nil {
if dir := filepath.Dir(exe); !slices.Contains(dirs, dir) {
dirs = append(dirs, dir)
}
}
for _, dir := range dirs {
for _, name := range defaultConfigFileNames {
candidate := filepath.Join(dir, name)
if stat, err := os.Stat(candidate); err == nil && !stat.IsDir() {
fmt.Fprintf(cmd.ErrOrStderr(), "using config file %q\n", candidate)
return candidate, nil
}
}
}
return "", fmt.Errorf("no %s found in %s, pass one with --config",
strings.Join(defaultConfigFileNames, " or "), strings.Join(dirs, " or "))
}