8 Commits

Author SHA1 Message Date
c483a1056f v0.8.0
Some checks failed
ci/woodpecker/push/publish-docs Pipeline was successful
ci/woodpecker/tag/gitea Pipeline was successful
ci/woodpecker/tag/publish-docs Pipeline was successful
ci/woodpecker/push/go-lint Pipeline failed
ci/woodpecker/release/publish-docs Pipeline was successful
2025-02-15 23:00:10 -06:00
3b9f569310 CI config changed
Some checks failed
ci/woodpecker/push/publish-docs Pipeline failed
2025-02-15 22:54:11 -06:00
843be7968b CI config changed 2025-02-15 22:50:44 -06:00
d477d850ac CI config changed 2025-02-15 22:46:49 -06:00
8eb3229af7 v0.8.0 2025-02-15 22:29:19 -06:00
d89a208bbd v0.8.0 2025-02-15 22:28:01 -06:00
0d28d6afcf breaking changes to keys 2025-02-15 22:27:11 -06:00
7c42a9a7cd v0.7.8
Some checks failed
ci/woodpecker/push/publish-docs Pipeline was successful
ci/woodpecker/tag/publish-docs Pipeline was successful
ci/woodpecker/tag/gitea Pipeline failed
2025-02-14 14:46:10 -06:00
13 changed files with 75 additions and 32 deletions

4
.changes/v0.7.8.md Normal file
View File

@ -0,0 +1,4 @@
## v0.7.8 - 2025-02-14
### Fixed
* Github CI config
* v0.7.1: Incorrect local config file loading logic caused files to not be detected

6
.changes/v0.8.0.md Normal file
View File

@ -0,0 +1,6 @@
## v0.8.0 - 2025-02-15
### Changed
* Breaking: `cmd-lists` key changed to `cmdLists`
* Properly load list config
* Config file loading properly errors
* CI Configs

View File

@ -15,11 +15,11 @@ jobs:
goreleaser: goreleaser:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- run: git fetch --force --tags - run: git fetch --force --tags
- uses: actions/setup-go@v4 - uses: actions/setup-go@v5
with: with:
go-version: '1.23' go-version: '1.23'
cache: true cache: true
@ -34,7 +34,7 @@ jobs:
with: with:
distribution: goreleaser distribution: goreleaser
version: 2.7.0 version: 2.7.0
run: goreleaser release --release-notes=".changes/$(go run backy.go version -V).md" -f .goreleaser/github.yml --clean args: release --release-notes=".changes/${{ env.GIT_TAG_NAME }}.md" -f .goreleaser/github.yml --clean
env: env:
GITHUB_TOKEN: ${{ secrets.GORELEASER_TOKEN }} GITHUB_TOKEN: ${{ secrets.GORELEASER_TOKEN }}
# GIT_TAG_NAME: ${{ steps.tagName.outputs.tag }} GIT_TAG_NAME: ${{ steps.tagName.outputs.tag }}

8
.gitignore vendored
View File

@ -3,4 +3,10 @@ dist/
.codegpt .codegpt
*.log *.log
*.sh *.sh
*.yaml
*.yml
+.changie.yaml
+.changes/

View File

@ -6,7 +6,10 @@ steps:
- go mod tidy - go mod tidy
- go install github.com/goreleaser/goreleaser/v2@v2.7.0 - go install github.com/goreleaser/goreleaser/v2@v2.7.0
- goreleaser release -f .goreleaser/gitea.yml --release-notes=".changes/$(go run backy.go version -V).md" - goreleaser release -f .goreleaser/gitea.yml --release-notes=".changes/$(go run backy.go version -V).md"
secrets: [ gitea_token ] environment:
GITEA_TOKEN:
from_secret: gitea_token
when: when:
event: tag event: tag
# release: # release:

View File

@ -23,7 +23,14 @@ steps:
- echo "$SSH_DEPLOY_KEY" | tr -d '\r' | DISPLAY=":0.0" SSH_ASKPASS=~/.ssh/.print_ssh_password setsid ssh-add - - echo "$SSH_DEPLOY_KEY" | tr -d '\r' | DISPLAY=":0.0" SSH_ASKPASS=~/.ssh/.print_ssh_password setsid ssh-add -
- rsync -atv --delete --progress public/ backy@backy.cybershell.xyz:docs - rsync -atv --delete --progress public/ backy@backy.cybershell.xyz:docs
- rsync -atv --delete --progress vangen/ backy@backy.cybershell.xyz:vangen-go - rsync -atv --delete --progress vangen/ backy@backy.cybershell.xyz:vangen-go
secrets: [ ssh_host_key, ssh_deploy_key, ssh_passphrase ] environment:
SSH_HOST_KEY:
from_secret: ssh_host_key
SSH_DEPLOY_KEY:
from_secret: ssh_deploy_key
SSH_PASSPHRASE:
from_secret: ssh_passphrase
when: when:
- branch: master - branch: master
- path: 'docs/**'

View File

@ -6,6 +6,18 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
and is generated by [Changie](https://github.com/miniscruff/changie). and is generated by [Changie](https://github.com/miniscruff/changie).
## v0.8.0 - 2025-02-15
### Changed
* Breaking: `cmd-lists` key changed to `cmdLists`
* Properly load list config
* Config file loading properly errors
* CI Configs
## v0.7.8 - 2025-02-14
### Fixed
* Github CI config
* v0.7.1: Incorrect local config file loading logic caused files to not be detected
## v0.7.7 - 2025-02-14 ## v0.7.7 - 2025-02-14
### Fixed ### Fixed
* v0.7.1: Incorrect local config file loading logic caused files to not be detected * v0.7.1: Incorrect local config file loading logic caused files to not be detected

View File

@ -7,7 +7,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
const versionStr = "0.7.7" const versionStr = "0.8.0"
var ( var (
versionCmd = &cobra.Command{ versionCmd = &cobra.Command{

View File

@ -2,7 +2,7 @@
title: "Command Lists" title: "Command Lists"
weight: 2 weight: 2
description: > description: >
This page tells you how to get use command lists. This page tells you how to use command lists.
--- ---
Command lists are for executing commands in sequence and getting notifications from them. Command lists are for executing commands in sequence and getting notifications from them.
@ -11,8 +11,8 @@ The top-level object key can be anything you want but not the same as another.
Lists can go in a separate file. Command lists should be in a separate file if: Lists can go in a separate file. Command lists should be in a separate file if:
1. key 'cmd-lists.file' is specified 1. key 'cmdLists.file' is specified
2. lists.yml or lists.yaml is found in the same directory as the backy config file 2. lists.yml or lists.yaml is found in the same directory as the backy config file (this includes remote config files as of v0.7.0)
{{% notice info %}} {{% notice info %}}
The lists file is also checked in remote resources. The lists file is also checked in remote resources.
@ -70,14 +70,14 @@ Name is optional. If name is not defined, name will be the object's map key.
Backy also has a cron mode, so one can run `backy cron` and start a process that schedules jobs to run at times defined in the configuration file. Backy also has a cron mode, so one can run `backy cron` and start a process that schedules jobs to run at times defined in the configuration file.
Adding `cron: 0 0 1 * * *` to a `cmd-lists` object will schedule the list at 1 in the morning. See [https://crontab.guru/](https://crontab.guru/) for reference. Adding `cron: 0 0 1 * * *` to a `cmdLists` object will schedule the list at 1 in the morning. See [https://crontab.guru/](https://crontab.guru/) for reference.
{{% notice tip %}} {{% notice tip %}}
Note: Backy uses the second field of cron, so add anything except `*` to the beginning of a regular cron expression. Note: Backy uses the second field of cron, so add anything except `*` to the beginning of a regular cron expression.
{{% /notice %}} {{% /notice %}}
```yaml {lineNos="true" wrap="true" title="yaml"} ```yaml {lineNos="true" wrap="true" title="yaml"}
cmd-lists: cmdLists:
  docker-container-backup: # this can be any name you want   docker-container-backup: # this can be any name you want
    # all commands have to be defined     # all commands have to be defined
    order:     order:

View File

@ -48,7 +48,7 @@ commands:
To execute groups of commands in sequence, use a list configuration. To execute groups of commands in sequence, use a list configuration.
```yaml ```yaml
cmd-lists: cmdLists:
cmds-to-run: # this can be any name you want cmds-to-run: # this can be any name you want
# all commands have to be defined in the commands section # all commands have to be defined in the commands section
order: order:
@ -97,7 +97,7 @@ hosts:
The notifications object can have two forms. The notifications object can have two forms.
For more, [see the notification object documentation](/config/notifications). The top-level map key is id that has to be referenced by the `cmd-lists` key `notifications`. For more, [see the notification object documentation](/config/notifications). The top-level map key is id that has to be referenced by the `cmdLists` key `notifications`.
```yaml ```yaml
notifications: notifications:

View File

@ -90,7 +90,6 @@ func (opts *ConfigOpts) InitConfig() {
} else { } else {
loadDefaultConfigFiles(fetcher, configFiles, backyKoanf, opts) loadDefaultConfigFiles(fetcher, configFiles, backyKoanf, opts)
} }
opts.koanf = backyKoanf opts.koanf = backyKoanf
} }
@ -117,7 +116,9 @@ func loadDefaultConfigFiles(fetcher remotefetcher.RemoteFetcher, configFiles []s
if data != nil { if data != nil {
if err := k.Load(rawbytes.Provider(data), yaml.Parser()); err == nil { if err := k.Load(rawbytes.Provider(data), yaml.Parser()); err == nil {
continue break
} else {
logging.ExitWithMSG(fmt.Sprintf("error loading config from file %s: %v", c, err), 1, &opts.Logger)
} }
} }
} }
@ -230,7 +231,7 @@ func setupLogger(opts *ConfigOpts) zerolog.Logger {
func unmarshalConfig(k *koanf.Koanf, key string, target interface{}, log zerolog.Logger) { func unmarshalConfig(k *koanf.Koanf, key string, target interface{}, log zerolog.Logger) {
if err := k.UnmarshalWithConf(key, target, koanf.UnmarshalConf{Tag: "yaml"}); err != nil { if err := k.UnmarshalWithConf(key, target, koanf.UnmarshalConf{Tag: "yaml"}); err != nil {
logging.ExitWithMSG(fmt.Sprintf("error unmarshalling %s struct: %v", key, err), 1, &log) logging.ExitWithMSG(fmt.Sprintf("error unmarshalling key %s into struct: %v", key, err), 1, &log)
} }
} }
@ -274,10 +275,13 @@ func loadCommandLists(opts *ConfigOpts, backyKoanf *koanf.Koanf) {
// if config file is remote, use the directory of the remote file // if config file is remote, use the directory of the remote file
if isRemoteURL(opts.ConfigFilePath) { if isRemoteURL(opts.ConfigFilePath) {
_, u = getRemoteDir(opts.ConfigFilePath) _, u = getRemoteDir(opts.ConfigFilePath)
// // Still use local list files if a remote config file is used, but use them last
listConfigFiles = []string{u.JoinPath("lists.yml").String(), u.JoinPath("lists.yaml").String()} listConfigFiles = []string{u.JoinPath("lists.yml").String(), u.JoinPath("lists.yaml").String()}
} else { } else {
backyConfigFileDir = path.Dir(opts.ConfigFilePath) backyConfigFileDir = path.Dir(opts.ConfigFilePath)
// println("backyConfigFileDir", backyConfigFileDir)
listConfigFiles = []string{ listConfigFiles = []string{
// "./lists.yml", "./lists.yaml",
path.Join(backyConfigFileDir, "lists.yml"), path.Join(backyConfigFileDir, "lists.yml"),
path.Join(backyConfigFileDir, "lists.yaml"), path.Join(backyConfigFileDir, "lists.yaml"),
} }
@ -291,9 +295,9 @@ func loadCommandLists(opts *ConfigOpts, backyKoanf *koanf.Koanf) {
} }
} }
if backyKoanf.Exists("cmd-lists") { if backyKoanf.Exists("cmdLists") {
unmarshalConfig(backyKoanf, "cmd-lists", &opts.CmdConfigLists, opts.Logger) unmarshalConfig(backyKoanf, "cmdLists", &opts.CmdConfigLists, opts.Logger)
if backyKoanf.Exists("cmd-lists.file") { if backyKoanf.Exists("cmdLists.file") {
loadCmdListsFile(backyKoanf, listsConfig, opts) loadCmdListsFile(backyKoanf, listsConfig, opts)
} }
} }
@ -319,6 +323,7 @@ func loadListConfigFile(filePath string, k *koanf.Koanf, opts *ConfigOpts) bool
if err != nil { if err != nil {
// if file not found, ignore // if file not found, ignore
if errors.Is(err, remotefetcher.ErrIgnoreFileNotFound) { if errors.Is(err, remotefetcher.ErrIgnoreFileNotFound) {
println("File not found", filePath)
return true return true
} }
@ -334,12 +339,13 @@ func loadListConfigFile(filePath string, k *koanf.Koanf, opts *ConfigOpts) bool
return false return false
} }
unmarshalConfig(k, "cmdLists", &opts.CmdConfigLists, opts.Logger)
opts.CmdListFile = filePath opts.CmdListFile = filePath
return true return true
} }
func loadCmdListsFile(backyKoanf *koanf.Koanf, listsConfig *koanf.Koanf, opts *ConfigOpts) { func loadCmdListsFile(backyKoanf *koanf.Koanf, listsConfig *koanf.Koanf, opts *ConfigOpts) {
opts.CmdListFile = strings.TrimSpace(backyKoanf.String("cmd-lists.file")) opts.CmdListFile = strings.TrimSpace(backyKoanf.String("cmdLists.file"))
if !path.IsAbs(opts.CmdListFile) { if !path.IsAbs(opts.CmdListFile) {
opts.CmdListFile = path.Join(path.Dir(opts.ConfigFilePath), opts.CmdListFile) opts.CmdListFile = path.Join(path.Dir(opts.ConfigFilePath), opts.CmdListFile)
} }
@ -359,14 +365,16 @@ func loadCmdListsFile(backyKoanf *koanf.Koanf, listsConfig *koanf.Koanf, opts *C
logging.ExitWithMSG(fmt.Sprintf("error loading config: %v", err), 1, &opts.Logger) logging.ExitWithMSG(fmt.Sprintf("error loading config: %v", err), 1, &opts.Logger)
} }
unmarshalConfig(listsConfig, "cmd-lists", &opts.CmdConfigLists, opts.Logger) unmarshalConfig(listsConfig, "cmdLists", &opts.CmdConfigLists, opts.Logger)
opts.Logger.Info().Str("using lists config file", opts.CmdListFile).Send() opts.Logger.Info().Str("using lists config file", opts.CmdListFile).Send()
} }
func validateCommandLists(opts *ConfigOpts) { func validateCommandLists(opts *ConfigOpts) {
var cmdNotFoundSliceErr []error var cmdNotFoundSliceErr []error
for cmdListName, cmdList := range opts.CmdConfigLists { for cmdListName, cmdList := range opts.CmdConfigLists {
// if cron is enabled and cron is not set, delete the list
if opts.cronEnabled && strings.TrimSpace(cmdList.Cron) == "" { if opts.cronEnabled && strings.TrimSpace(cmdList.Cron) == "" {
opts.Logger.Debug().Str("cron", "enabled").Str("list", cmdListName).Msg("cron not set, deleting list")
delete(opts.CmdConfigLists, cmdListName) delete(opts.CmdConfigLists, cmdListName)
continue continue
} }
@ -406,9 +414,9 @@ func getLoggingKeyFromConfig(key string) string {
return fmt.Sprintf("logging.%s", key) return fmt.Sprintf("logging.%s", key)
} }
func getCmdListFromConfig(list string) string { // func getCmdListFromConfig(list string) string {
return fmt.Sprintf("cmd-lists.%s", list) // return fmt.Sprintf("cmdLists.%s", list)
} // }
func (opts *ConfigOpts) setupVault() error { func (opts *ConfigOpts) setupVault() error {
if !opts.koanf.Bool("vault.enabled") { if !opts.koanf.Bool("vault.enabled") {

View File

@ -17,10 +17,7 @@ func (opts *ConfigOpts) Cron() {
s := gocron.NewScheduler(time.Local) s := gocron.NewScheduler(time.Local)
s.TagsUnique() s.TagsUnique()
cmdLists := opts.CmdConfigLists cmdLists := opts.CmdConfigLists
for listName, config := range cmdLists { for _, config := range cmdLists {
if config.Name == "" {
config.Name = listName
}
cron := strings.TrimSpace(config.Cron) cron := strings.TrimSpace(config.Cron)
if cron != "" { if cron != "" {

View File

@ -187,7 +187,7 @@ type (
// CmdConfigLists holds the lists of commands to be run in order. // CmdConfigLists holds the lists of commands to be run in order.
// Key is the command list name. // Key is the command list name.
CmdConfigLists map[string]*CmdList `yaml:"cmd-lists"` CmdConfigLists map[string]*CmdList `yaml:"cmdLists"`
// Hosts holds the Host config. // Hosts holds the Host config.
// key is the host. // key is the host.