forked from toolshed/abra
Compare commits
9 Commits
main
...
urfave-mig
Author | SHA1 | Date | |
---|---|---|---|
7ddfd22133 | |||
c3f0d15920 | |||
edb542c653 | |||
4580ea9dc8 | |||
878247e46d | |||
ef547aed25 | |||
2c9e13d3d4 | |||
ca37621ce3 | |||
16aeb441e7 |
@ -1,34 +1,35 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var AppCommand = cli.Command{
|
||||
Name: "app",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Manage apps",
|
||||
ArgsUsage: "<domain>",
|
||||
Subcommands: []cli.Command{
|
||||
appBackupCommand,
|
||||
appCheckCommand,
|
||||
appCmdCommand,
|
||||
appConfigCommand,
|
||||
appCpCommand,
|
||||
appDeployCommand,
|
||||
appListCommand,
|
||||
appLogsCommand,
|
||||
appNewCommand,
|
||||
appPsCommand,
|
||||
appRemoveCommand,
|
||||
appRestartCommand,
|
||||
appRestoreCommand,
|
||||
appRollbackCommand,
|
||||
appRunCommand,
|
||||
appSecretCommand,
|
||||
appServicesCommand,
|
||||
appUndeployCommand,
|
||||
appUpgradeCommand,
|
||||
appVolumeCommand,
|
||||
Name: "app",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Manage apps",
|
||||
UsageText: "abra app [command] [options] [arguments]",
|
||||
HideHelpCommand: true,
|
||||
Commands: []*cli.Command{
|
||||
&appBackupCommand,
|
||||
&appCheckCommand,
|
||||
&appCmdCommand,
|
||||
&appConfigCommand,
|
||||
&appCpCommand,
|
||||
&appDeployCommand,
|
||||
&appListCommand,
|
||||
&appLogsCommand,
|
||||
&appNewCommand,
|
||||
&appPsCommand,
|
||||
&appRemoveCommand,
|
||||
&appRestartCommand,
|
||||
&appRestoreCommand,
|
||||
&appRollbackCommand,
|
||||
&appRunCommand,
|
||||
&appSecretCommand,
|
||||
&appServicesCommand,
|
||||
&appUndeployCommand,
|
||||
&appUpgradeCommand,
|
||||
&appVolumeCommand,
|
||||
},
|
||||
}
|
||||
|
@ -1,32 +1,36 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var snapshot string
|
||||
var snapshotFlag = &cli.StringFlag{
|
||||
Name: "snapshot, s",
|
||||
Name: "snapshot",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "Lists specific snapshot",
|
||||
Destination: &snapshot,
|
||||
}
|
||||
|
||||
var includePath string
|
||||
var includePathFlag = &cli.StringFlag{
|
||||
Name: "path, p",
|
||||
Name: "path",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Include path",
|
||||
Destination: &includePath,
|
||||
}
|
||||
|
||||
var resticRepo string
|
||||
var resticRepoFlag = &cli.StringFlag{
|
||||
Name: "repo, r",
|
||||
Name: "repo",
|
||||
Aliases: []string{"r"},
|
||||
Usage: "Restic repository",
|
||||
Destination: &resticRepo,
|
||||
}
|
||||
@ -35,16 +39,17 @@ var appBackupListCommand = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
snapshotFlag,
|
||||
includePathFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "List all backups",
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "List all backups",
|
||||
EnableShellCompletion: true,
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app backup list [options] <domain>",
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
|
||||
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
log.Fatal(err)
|
||||
@ -82,16 +87,17 @@ var appBackupDownloadCommand = cli.Command{
|
||||
Name: "download",
|
||||
Aliases: []string{"d"},
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
snapshotFlag,
|
||||
includePathFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Download a backup",
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Download a backup",
|
||||
UsageText: "abra app backup download [options] <domain>",
|
||||
HideHelpCommand: true,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
|
||||
if err := app.Recipe.EnsureExists(); err != nil {
|
||||
log.Fatal(err)
|
||||
@ -153,15 +159,16 @@ var appBackupCreateCommand = cli.Command{
|
||||
Name: "create",
|
||||
Aliases: []string{"c"},
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
resticRepoFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Create a new backup",
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Create a new backup",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app backup create [options] <domain>",
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
|
||||
if err := app.Recipe.EnsureExists(); err != nil {
|
||||
log.Fatal(err)
|
||||
@ -211,15 +218,16 @@ var appBackupSnapshotsCommand = cli.Command{
|
||||
Name: "snapshots",
|
||||
Aliases: []string{"s"},
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
snapshotFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "List backup snapshots",
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "List backup snapshots",
|
||||
UsageText: "abra app backup snapshots [options] <domain>",
|
||||
HideHelpCommand: true,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
|
||||
if err := app.Recipe.EnsureExists(); err != nil {
|
||||
log.Fatal(err)
|
||||
@ -266,14 +274,15 @@ var appBackupSnapshotsCommand = cli.Command{
|
||||
}
|
||||
|
||||
var appBackupCommand = cli.Command{
|
||||
Name: "backup",
|
||||
Aliases: []string{"b"},
|
||||
Usage: "Manage app backups",
|
||||
ArgsUsage: "<domain>",
|
||||
Subcommands: []cli.Command{
|
||||
appBackupListCommand,
|
||||
appBackupSnapshotsCommand,
|
||||
appBackupDownloadCommand,
|
||||
appBackupCreateCommand,
|
||||
Name: "backup",
|
||||
Aliases: []string{"b"},
|
||||
Usage: "Manage app backups",
|
||||
UsageText: "abra app backup [command] [options] [arguments]",
|
||||
HideHelpCommand: true,
|
||||
Commands: []*cli.Command{
|
||||
&appBackupListCommand,
|
||||
&appBackupSnapshotsCommand,
|
||||
&appBackupDownloadCommand,
|
||||
&appBackupCreateCommand,
|
||||
},
|
||||
}
|
||||
|
@ -1,21 +1,21 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
appPkg "coopcloud.tech/abra/pkg/app"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var appCheckCommand = cli.Command{
|
||||
Name: "check",
|
||||
Aliases: []string{"chk"},
|
||||
Usage: "Ensure an app is well configured",
|
||||
Description: `
|
||||
This command compares env vars in both the app ".env" and recipe ".env.sample"
|
||||
file.
|
||||
Description: `Compare env vars in both the app ".env" and recipe ".env.sample" file.
|
||||
|
||||
The goal is to ensure that recipe ".env.sample" env vars are defined in your
|
||||
app ".env" file. Only env var definitions in the ".env.sample" which are
|
||||
@ -25,16 +25,17 @@ these env vars, then "check" will complain.
|
||||
Recipe maintainers may or may not provide defaults for env vars within their
|
||||
recipes regardless of commenting or not (e.g. through the use of
|
||||
${FOO:<default>} syntax). "check" does not confirm or deny this for you.`,
|
||||
ArgsUsage: "<domain>",
|
||||
UsageText: "abra app check [options] <domain>",
|
||||
HideHelpCommand: true,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.ChaosFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
|
||||
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@ -14,7 +15,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var appCmdCommand = cli.Command{
|
||||
@ -26,47 +27,45 @@ var appCmdCommand = cli.Command{
|
||||
These commands are bash functions, defined in the abra.sh of the recipe itself.
|
||||
They can be run within the context of a service (e.g. app) or locally on your
|
||||
work station by passing "--local". Arguments can be passed into these functions
|
||||
using the "-- <args>" syntax.
|
||||
using the "-- <cmd-args>" syntax.
|
||||
|
||||
**WARNING**: options must be passed directly after the sub-command "cmd".
|
||||
|
||||
EXAMPLE:
|
||||
|
||||
abra app cmd --local example.com app create_user -- me@example.com`,
|
||||
ArgsUsage: "<domain> [<service>] <command> [-- <args>]",
|
||||
**WARNING**: [options] must be passed directly after the "cmd" sub-command.`,
|
||||
UsageText: "abra app cmd [options] <domain> [<service>] <cmd> [-- <cmd-args>]",
|
||||
HideHelpCommand: true,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.LocalCmdFlag,
|
||||
internal.RemoteUserFlag,
|
||||
internal.TtyFlag,
|
||||
internal.OfflineFlag,
|
||||
internal.ChaosFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Subcommands: []cli.Command{appCmdListCommand},
|
||||
BashComplete: func(ctx *cli.Context) {
|
||||
args := ctx.Args()
|
||||
switch len(args) {
|
||||
Before: internal.SubCommandBefore,
|
||||
Commands: []*cli.Command{
|
||||
&appCmdListCommand,
|
||||
},
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: func(ctx context.Context, cmd *cli.Command) {
|
||||
args := cmd.Args()
|
||||
switch args.Len() {
|
||||
case 0:
|
||||
autocomplete.AppNameComplete(ctx)
|
||||
autocomplete.AppNameComplete(ctx, cmd)
|
||||
case 1:
|
||||
autocomplete.ServiceNameComplete(args.Get(0))
|
||||
case 2:
|
||||
cmdNameComplete(args.Get(0))
|
||||
}
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
|
||||
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if internal.LocalCmd && internal.RemoteUser != "" {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("cannot use --local & --user together"))
|
||||
internal.ShowSubcommandHelpAndError(cmd, errors.New("cannot use --local & --user together"))
|
||||
}
|
||||
|
||||
hasCmdArgs, parsedCmdArgs := parseCmdArgs(c.Args(), internal.LocalCmd)
|
||||
hasCmdArgs, parsedCmdArgs := parseCmdArgs(cmd.Args().Slice(), internal.LocalCmd)
|
||||
|
||||
if _, err := os.Stat(app.Recipe.AbraShPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
@ -76,11 +75,11 @@ EXAMPLE:
|
||||
}
|
||||
|
||||
if internal.LocalCmd {
|
||||
if !(len(c.Args()) >= 2) {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("missing arguments"))
|
||||
if !(cmd.Args().Len() >= 2) {
|
||||
internal.ShowSubcommandHelpAndError(cmd, errors.New("missing arguments"))
|
||||
}
|
||||
|
||||
cmdName := c.Args().Get(1)
|
||||
cmdName := cmd.Args().Get(1)
|
||||
if err := internal.EnsureCommand(app.Recipe.AbraShPath, app.Recipe.Name, cmdName); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -112,13 +111,13 @@ EXAMPLE:
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
if !(len(c.Args()) >= 3) {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("missing arguments"))
|
||||
if !(cmd.Args().Len() >= 3) {
|
||||
internal.ShowSubcommandHelpAndError(cmd, errors.New("missing arguments"))
|
||||
}
|
||||
|
||||
targetServiceName := c.Args().Get(1)
|
||||
targetServiceName := cmd.Args().Get(1)
|
||||
|
||||
cmdName := c.Args().Get(2)
|
||||
cmdName := cmd.Args().Get(2)
|
||||
if err := internal.EnsureCommand(app.Recipe.AbraShPath, app.Recipe.Name, cmdName); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -195,19 +194,19 @@ func cmdNameComplete(appName string) {
|
||||
}
|
||||
|
||||
var appCmdListCommand = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List all available commands",
|
||||
ArgsUsage: "<domain>",
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List all available commands",
|
||||
UsageText: "abra app cmd ls [options] <domain>",
|
||||
HideHelpCommand: true,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
internal.ChaosFlag,
|
||||
},
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
|
||||
if err := app.Recipe.EnsureExists(); err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
@ -10,24 +11,23 @@ import (
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var appConfigCommand = cli.Command{
|
||||
Name: "config",
|
||||
Aliases: []string{"cfg"},
|
||||
Usage: "Edit app config",
|
||||
ArgsUsage: "<domain>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
appName := c.Args().First()
|
||||
Name: "config",
|
||||
Aliases: []string{"cfg"},
|
||||
Usage: "Edit app config",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app config [options] <domain>",
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
appName := cmd.Args().First()
|
||||
|
||||
if appName == "" {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("no app provided"))
|
||||
internal.ShowSubcommandHelpAndError(cmd, errors.New("no app provided"))
|
||||
}
|
||||
|
||||
files, err := appPkg.LoadAppFiles("")
|
||||
@ -51,11 +51,11 @@ var appConfigCommand = cli.Command{
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command(ed, appFile.Path)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
c := exec.Command(ed, appFile.Path)
|
||||
c.Stdin = os.Stdin
|
||||
c.Stdout = os.Stdout
|
||||
c.Stderr = os.Stderr
|
||||
if err := c.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -22,21 +22,17 @@ import (
|
||||
dockerClient "github.com/docker/docker/client"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var appCpCommand = cli.Command{
|
||||
Name: "cp",
|
||||
Aliases: []string{"c"},
|
||||
ArgsUsage: "<domain> <src> <dst>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Copy files to/from a deployed app service",
|
||||
Description: `
|
||||
Copy files to and from any app service file system.
|
||||
Name: "cp",
|
||||
Aliases: []string{"c"},
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app cp [options] <domain> <src> <dst>",
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Copy files to/from a deployed app service",
|
||||
Description: `Copy files to and from any app service file system.
|
||||
|
||||
If you want to copy a myfile.txt to the root of the app service:
|
||||
|
||||
@ -44,18 +40,17 @@ If you want to copy a myfile.txt to the root of the app service:
|
||||
|
||||
And if you want to copy that file back to your current working directory locally:
|
||||
|
||||
abra app cp <domain> app:/myfile.txt .
|
||||
`,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
|
||||
abra app cp <domain> app:/myfile.txt`,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
src := c.Args().Get(1)
|
||||
dst := c.Args().Get(2)
|
||||
src := cmd.Args().Get(1)
|
||||
dst := cmd.Args().Get(2)
|
||||
if src == "" {
|
||||
log.Fatal("missing <src> argument")
|
||||
}
|
||||
|
@ -15,22 +15,21 @@ import (
|
||||
"coopcloud.tech/abra/pkg/lint"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var appDeployCommand = cli.Command{
|
||||
Name: "deploy",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "Deploy an app",
|
||||
ArgsUsage: "<domain> [<version>]",
|
||||
Name: "deploy",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "Deploy an app",
|
||||
ArgsUsage: "<domain> [<version>]",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app deploy [options] <domain> [<version>]",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.ForceFlag,
|
||||
internal.ChaosFlag,
|
||||
internal.NoDomainChecksFlag,
|
||||
internal.DontWaitConvergeFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `Deploy an app.
|
||||
@ -38,22 +37,18 @@ var appDeployCommand = cli.Command{
|
||||
This command supports chaos operations. Use "--chaos" to deploy your recipe
|
||||
checkout as-is. Recipe commit hashes are also supported values for
|
||||
"[<version>]". Please note, "upgrade"/"rollback" do not support chaos
|
||||
operations.
|
||||
|
||||
EXAMPLE:
|
||||
|
||||
abra app deploy foo.example.com
|
||||
abra app deploy foo.example.com 1.2.3+3.2.1
|
||||
abra app deploy foo.example.com 1e83340e`,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
operations.`,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
stackName := app.StackName()
|
||||
|
||||
specificVersion := c.Args().Get(1)
|
||||
specificVersion := cmd.Args().Get(1)
|
||||
if specificVersion == "" {
|
||||
specificVersion = app.Recipe.Version
|
||||
}
|
||||
|
||||
if specificVersion != "" && internal.Chaos {
|
||||
log.Fatal("cannot use <version> and --chaos together")
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
@ -12,13 +13,14 @@ import (
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/tagcmp"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
status bool
|
||||
statusFlag = &cli.BoolFlag{
|
||||
Name: "status, S",
|
||||
Name: "status",
|
||||
Aliases: []string{"S"},
|
||||
Usage: "Show app deployment status",
|
||||
Destination: &status,
|
||||
}
|
||||
@ -27,7 +29,8 @@ var (
|
||||
var (
|
||||
recipeFilter string
|
||||
recipeFlag = &cli.StringFlag{
|
||||
Name: "recipe, r",
|
||||
Name: "recipe",
|
||||
Aliases: []string{"r"},
|
||||
Value: "",
|
||||
Usage: "Show apps of a specific recipe",
|
||||
Destination: &recipeFilter,
|
||||
@ -37,7 +40,8 @@ var (
|
||||
var (
|
||||
listAppServer string
|
||||
listAppServerFlag = &cli.StringFlag{
|
||||
Name: "server, s",
|
||||
Name: "server",
|
||||
Aliases: []string{"s"},
|
||||
Value: "",
|
||||
Usage: "Show apps of a specific server",
|
||||
Destination: &listAppServer,
|
||||
@ -67,26 +71,24 @@ type serverStatus struct {
|
||||
}
|
||||
|
||||
var appListCommand = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List all managed apps",
|
||||
Description: `
|
||||
Read the local file system listing of apps and servers (e.g. ~/.abra/) to
|
||||
generate a report of all your apps.
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List all managed apps",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app list [options]",
|
||||
Description: `Generate a report of all managed apps.
|
||||
|
||||
By passing the "--status/-S" flag, you can query all your servers for the
|
||||
actual live deployment status. Depending on how many servers you manage, this
|
||||
can take some time.`,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.MachineReadableFlag,
|
||||
statusFlag,
|
||||
listAppServerFlag,
|
||||
recipeFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
appFiles, err := appPkg.LoadAppFiles(listAppServer)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -19,23 +19,24 @@ import (
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
dockerClient "github.com/docker/docker/client"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var appLogsCommand = cli.Command{
|
||||
Name: "logs",
|
||||
Aliases: []string{"l"},
|
||||
ArgsUsage: "<domain> [<service>]",
|
||||
Usage: "Tail app logs",
|
||||
Name: "logs",
|
||||
Aliases: []string{"l"},
|
||||
Usage: "Tail app logs",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app logs [options] <domain> [<service>]",
|
||||
Flags: []cli.Flag{
|
||||
internal.StdErrOnlyFlag,
|
||||
internal.SinceLogsFlag,
|
||||
internal.DebugFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
stackName := app.StackName()
|
||||
|
||||
if err := app.Recipe.EnsureExists(); err != nil {
|
||||
@ -56,7 +57,7 @@ var appLogsCommand = cli.Command{
|
||||
log.Fatalf("%s is not deployed?", app.Name)
|
||||
}
|
||||
|
||||
serviceName := c.Args().Get(1)
|
||||
serviceName := cmd.Args().Get(1)
|
||||
serviceNames := []string{}
|
||||
if serviceName != "" {
|
||||
serviceNames = []string{serviceName}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
@ -15,12 +16,13 @@ import (
|
||||
"coopcloud.tech/abra/pkg/secret"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
dockerClient "github.com/docker/docker/client"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var appNewDescription = `
|
||||
Creates a new app from a default recipe. This new app configuration is stored
|
||||
in your $ABRA_DIR directory under the appropriate server.
|
||||
var appNewDescription = `Creates a new app from a default recipe.
|
||||
|
||||
This new app configuration is stored in your $ABRA_DIR directory under the
|
||||
appropriate server.
|
||||
|
||||
This command does not deploy your app for you. You will need to run "abra app
|
||||
deploy <domain>" to do so.
|
||||
@ -43,28 +45,27 @@ var appNewCommand = cli.Command{
|
||||
Usage: "Create a new app",
|
||||
Description: appNewDescription,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.NewAppServerFlag,
|
||||
internal.DomainFlag,
|
||||
internal.PassFlag,
|
||||
internal.SecretsFlag,
|
||||
internal.OfflineFlag,
|
||||
internal.ChaosFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
ArgsUsage: "[<recipe>] [<version>]",
|
||||
BashComplete: func(ctx *cli.Context) {
|
||||
args := ctx.Args()
|
||||
switch len(args) {
|
||||
Before: internal.SubCommandBefore,
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app new [options] [<recipe>] [<version>]",
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: func(ctx context.Context, cmd *cli.Command) {
|
||||
args := cmd.Args()
|
||||
switch args.Len() {
|
||||
case 0:
|
||||
autocomplete.RecipeNameComplete(ctx)
|
||||
autocomplete.RecipeNameComplete(ctx, cmd)
|
||||
case 1:
|
||||
autocomplete.RecipeVersionComplete(ctx.Args().Get(0))
|
||||
autocomplete.RecipeVersionComplete(cmd.Args().Get(0))
|
||||
}
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
recipe := internal.ValidateRecipe(c)
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
recipe := internal.ValidateRecipe(cmd)
|
||||
|
||||
if !internal.Chaos {
|
||||
if err := recipe.EnsureIsClean(); err != nil {
|
||||
@ -75,7 +76,7 @@ var appNewCommand = cli.Command{
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
if c.Args().Get(1) == "" {
|
||||
if cmd.Args().Get(1) == "" {
|
||||
var version string
|
||||
|
||||
recipeVersions, err := recipe.GetRecipeVersions()
|
||||
@ -100,7 +101,7 @@ var appNewCommand = cli.Command{
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if _, err := recipe.EnsureVersion(c.Args().Get(1)); err != nil {
|
||||
if _, err := recipe.EnsureVersion(cmd.Args().Get(1)); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -17,23 +17,24 @@ import (
|
||||
containerTypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
dockerClient "github.com/docker/docker/client"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var appPsCommand = cli.Command{
|
||||
Name: "ps",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Check app status",
|
||||
ArgsUsage: "<domain>",
|
||||
Description: "Show status of a deployed app.",
|
||||
Name: "ps",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Check app status",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app ps [options] <domain>",
|
||||
Description: "Show status of a deployed app.",
|
||||
Flags: []cli.Flag{
|
||||
internal.MachineReadableFlag,
|
||||
internal.DebugFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
if err := app.Recipe.Ensure(false, false); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -12,16 +12,16 @@ import (
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var appRemoveCommand = cli.Command{
|
||||
Name: "remove",
|
||||
Aliases: []string{"rm"},
|
||||
ArgsUsage: "<domain>",
|
||||
Usage: "Remove all app data, locally and remotely",
|
||||
Description: `
|
||||
This command removes everything related to an app which is already undeployed.
|
||||
Name: "remove",
|
||||
Aliases: []string{"rm"},
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app remove [options] <domain>",
|
||||
Usage: "Remove all app data, locally and remotely",
|
||||
Description: `Remove everything related to an app which is already undeployed.
|
||||
|
||||
By default, it will prompt for confirmation before proceeding. All secrets,
|
||||
volumes and the local app env file will be deleted.
|
||||
@ -39,14 +39,12 @@ To delete everything without prompt, use the "--force/-f" or the "--no-input/n"
|
||||
flag.`,
|
||||
Flags: []cli.Flag{
|
||||
internal.ForceFlag,
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
|
||||
if !internal.Force && !internal.NoInput {
|
||||
response := false
|
||||
|
@ -12,41 +12,36 @@ import (
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
upstream "coopcloud.tech/abra/pkg/upstream/service"
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var appRestartCommand = cli.Command{
|
||||
Name: "restart",
|
||||
Aliases: []string{"re"},
|
||||
Usage: "Restart an app",
|
||||
ArgsUsage: "<domain> [<service>]",
|
||||
Name: "restart",
|
||||
Aliases: []string{"re"},
|
||||
Usage: "Restart an app",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app restart [options] <domain> [<service>]",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
internal.AllServicesFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
This command restarts services within a deployed app.
|
||||
Description: `This command restarts services within a deployed app.
|
||||
|
||||
Run "abra app ps <domain>" to see a list of service names.
|
||||
|
||||
Pass "--all-services/-a" to restart all services.
|
||||
|
||||
EXAMPLE:
|
||||
|
||||
abra app restart example.com app`,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Pass "--all-services/-a" to restart all services.`,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
if err := app.Recipe.Ensure(false, false); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
serviceName := c.Args().Get(1)
|
||||
serviceName := cmd.Args().Get(1)
|
||||
if serviceName == "" && !internal.AllServices {
|
||||
err := errors.New("missing <service>")
|
||||
internal.ShowSubcommandHelpAndError(c, err)
|
||||
internal.ShowSubcommandHelpAndError(cmd, err)
|
||||
}
|
||||
|
||||
if serviceName != "" && internal.AllServices {
|
||||
|
@ -1,36 +1,38 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var targetPath string
|
||||
var targetPathFlag = &cli.StringFlag{
|
||||
Name: "target, t",
|
||||
Name: "target",
|
||||
Aliases: []string{"t"},
|
||||
Usage: "Target path",
|
||||
Destination: &targetPath,
|
||||
}
|
||||
|
||||
var appRestoreCommand = cli.Command{
|
||||
Name: "restore",
|
||||
Aliases: []string{"rs"},
|
||||
Usage: "Restore an app backup",
|
||||
ArgsUsage: "<domain> <service>",
|
||||
Name: "restore",
|
||||
Aliases: []string{"rs"},
|
||||
Usage: "Restore an app backup",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app restore [options] <domain> <service>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
targetPathFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -15,39 +15,32 @@ import (
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var appRollbackCommand = cli.Command{
|
||||
Name: "rollback",
|
||||
Aliases: []string{"rl"},
|
||||
Usage: "Roll an app back to a previous version",
|
||||
ArgsUsage: "<domain> [<version>]",
|
||||
Name: "rollback",
|
||||
Aliases: []string{"rl"},
|
||||
Usage: "Roll an app back to a previous version",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app rollback [options] <domain> [<version>]",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.ForceFlag,
|
||||
internal.NoDomainChecksFlag,
|
||||
internal.DontWaitConvergeFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
This command rolls an app back to a previous version.
|
||||
Description: `This command rolls an app back to a previous version.
|
||||
|
||||
Unlike "deploy", chaos operations are not supported here. Only recipe versions
|
||||
are supported values for "[<version>]".
|
||||
|
||||
A rollback can be destructive, please ensure you have a copy of your app data
|
||||
beforehand.
|
||||
|
||||
EXAMPLE:
|
||||
|
||||
abra app rollback foo.example.com
|
||||
abra app rollback foo.example.com 1.2.3+3.2.1`,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
beforehand.`,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
stackName := app.StackName()
|
||||
|
||||
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
@ -85,10 +78,11 @@ EXAMPLE:
|
||||
log.Warnf("failed to determine deployed version of %s", app.Name)
|
||||
}
|
||||
|
||||
specificVersion := c.Args().Get(1)
|
||||
specificVersion := cmd.Args().Get(1)
|
||||
if specificVersion == "" {
|
||||
specificVersion = app.Recipe.Version
|
||||
}
|
||||
|
||||
if specificVersion != "" {
|
||||
parsedDeployedVersion, err := tagcmp.Parse(deployMeta.Version)
|
||||
if err != nil {
|
||||
|
@ -14,19 +14,21 @@ import (
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var user string
|
||||
var userFlag = &cli.StringFlag{
|
||||
Name: "user, u",
|
||||
Name: "user",
|
||||
Aliases: []string{"u"},
|
||||
Value: "",
|
||||
Destination: &user,
|
||||
}
|
||||
|
||||
var noTTY bool
|
||||
var noTTYFlag = &cli.BoolFlag{
|
||||
Name: "no-tty, t",
|
||||
Name: "no-tty",
|
||||
Aliases: []string{"t"},
|
||||
Destination: &noTTY,
|
||||
}
|
||||
|
||||
@ -34,23 +36,24 @@ var appRunCommand = cli.Command{
|
||||
Name: "run",
|
||||
Aliases: []string{"r"},
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
noTTYFlag,
|
||||
userFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
ArgsUsage: "<domain> <service> <args>...",
|
||||
Usage: "Run a command in a service container",
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
UsageText: "abra app run [options] <domain> <service> <args>",
|
||||
Usage: "Run a command in an app service",
|
||||
HideHelpCommand: true,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
|
||||
if len(c.Args()) < 2 {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("no <service> provided?"))
|
||||
if cmd.Args().Len() < 2 {
|
||||
internal.ShowSubcommandHelpAndError(cmd, errors.New("no <service> provided?"))
|
||||
}
|
||||
|
||||
if len(c.Args()) < 3 {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("no <args> provided?"))
|
||||
if cmd.Args().Len() < 3 {
|
||||
internal.ShowSubcommandHelpAndError(cmd, errors.New("no <args> provided?"))
|
||||
}
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
@ -58,7 +61,7 @@ var appRunCommand = cli.Command{
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
serviceName := c.Args().Get(1)
|
||||
serviceName := cmd.Args().Get(1)
|
||||
stackAndServiceName := fmt.Sprintf("^%s_%s", app.StackName(), serviceName)
|
||||
filters := filters.NewArgs()
|
||||
filters.Add("name", stackAndServiceName)
|
||||
@ -68,12 +71,12 @@ var appRunCommand = cli.Command{
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
cmd := c.Args()[2:]
|
||||
c := cmd.Args().Slice()[2:]
|
||||
execCreateOpts := types.ExecConfig{
|
||||
AttachStderr: true,
|
||||
AttachStdin: true,
|
||||
AttachStdout: true,
|
||||
Cmd: cmd,
|
||||
Cmd: c,
|
||||
Detach: false,
|
||||
Tty: true,
|
||||
}
|
||||
|
@ -17,13 +17,14 @@ import (
|
||||
"coopcloud.tech/abra/pkg/secret"
|
||||
"github.com/docker/docker/api/types"
|
||||
dockerClient "github.com/docker/docker/client"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
allSecrets bool
|
||||
allSecretsFlag = &cli.BoolFlag{
|
||||
Name: "all, a",
|
||||
Name: "all",
|
||||
Aliases: []string{"a"},
|
||||
Destination: &allSecrets,
|
||||
Usage: "Generate all secrets",
|
||||
}
|
||||
@ -32,41 +33,42 @@ var (
|
||||
var (
|
||||
rmAllSecrets bool
|
||||
rmAllSecretsFlag = &cli.BoolFlag{
|
||||
Name: "all, a",
|
||||
Name: "all",
|
||||
Aliases: []string{"a"},
|
||||
Destination: &rmAllSecrets,
|
||||
Usage: "Remove all secrets",
|
||||
}
|
||||
)
|
||||
|
||||
var appSecretGenerateCommand = cli.Command{
|
||||
Name: "generate",
|
||||
Aliases: []string{"g"},
|
||||
Usage: "Generate secrets",
|
||||
ArgsUsage: "<domain> <secret> <version>",
|
||||
Name: "generate",
|
||||
Aliases: []string{"g"},
|
||||
Usage: "Generate secrets",
|
||||
UsageText: "abra app secret generate [options] <domain> <secret> <version>",
|
||||
HideHelpCommand: true,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
allSecretsFlag,
|
||||
internal.PassFlag,
|
||||
internal.MachineReadableFlag,
|
||||
internal.OfflineFlag,
|
||||
internal.ChaosFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if len(c.Args()) == 1 && !allSecrets {
|
||||
if cmd.Args().Len() == 1 && !allSecrets {
|
||||
err := errors.New("missing arguments <secret>/<version> or '--all'")
|
||||
internal.ShowSubcommandHelpAndError(c, err)
|
||||
internal.ShowSubcommandHelpAndError(cmd, err)
|
||||
}
|
||||
|
||||
if c.Args().Get(1) != "" && allSecrets {
|
||||
if cmd.Args().Get(1) != "" && allSecrets {
|
||||
err := errors.New("cannot use '<secret> <version>' and '--all' together")
|
||||
internal.ShowSubcommandHelpAndError(c, err)
|
||||
internal.ShowSubcommandHelpAndError(cmd, err)
|
||||
}
|
||||
|
||||
composeFiles, err := app.Recipe.GetComposeFiles(app.Env)
|
||||
@ -80,8 +82,8 @@ var appSecretGenerateCommand = cli.Command{
|
||||
}
|
||||
|
||||
if !allSecrets {
|
||||
secretName := c.Args().Get(1)
|
||||
secretVersion := c.Args().Get(2)
|
||||
secretName := cmd.Args().Get(1)
|
||||
secretVersion := cmd.Args().Get(2)
|
||||
s, ok := secrets[secretName]
|
||||
if !ok {
|
||||
log.Fatalf("%s doesn't exist in the env config?", secretName)
|
||||
@ -142,26 +144,21 @@ var appSecretInsertCommand = cli.Command{
|
||||
internal.FileFlag,
|
||||
internal.TrimFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
ArgsUsage: "<domain> <secret-name> <version> <data>",
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Description: `
|
||||
This command inserts a secret into an app environment.
|
||||
Before: internal.SubCommandBefore,
|
||||
UsageText: "abra app secret insert [options] <domain> <secret> <version> <data>",
|
||||
HideHelpCommand: true,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Description: `This command inserts a secret into an app environment.
|
||||
|
||||
This can be useful when you want to manually generate secrets for an app
|
||||
environment. Typically, you can let Abra generate them for you on app creation
|
||||
(see "abra app new --secrets" for more).
|
||||
(see "abra app new --secrets" for more).`,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
|
||||
Example:
|
||||
|
||||
abra app secret insert myapp db_pass v1 mySecretPassword
|
||||
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
|
||||
if len(c.Args()) != 4 {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("missing arguments?"))
|
||||
if cmd.Args().Len() != 4 {
|
||||
internal.ShowSubcommandHelpAndError(cmd, errors.New("missing arguments?"))
|
||||
}
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
@ -169,9 +166,9 @@ Example:
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
name := c.Args().Get(1)
|
||||
version := c.Args().Get(2)
|
||||
data := c.Args().Get(3)
|
||||
name := cmd.Args().Get(1)
|
||||
version := cmd.Args().Get(2)
|
||||
data := cmd.Args().Get(3)
|
||||
|
||||
if internal.File {
|
||||
raw, err := os.ReadFile(data)
|
||||
@ -233,9 +230,10 @@ var appSecretRmCommand = cli.Command{
|
||||
internal.OfflineFlag,
|
||||
internal.ChaosFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
ArgsUsage: "<domain> [<secret-name>]",
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Before: internal.SubCommandBefore,
|
||||
ArgsUsage: "<domain> [<secret-name>]",
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Description: `
|
||||
This command removes app secrets.
|
||||
|
||||
@ -243,8 +241,8 @@ Example:
|
||||
|
||||
abra app secret remove myapp db_pass
|
||||
`,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -259,12 +257,12 @@ Example:
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if c.Args().Get(1) != "" && rmAllSecrets {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("cannot use '<secret-name>' and '--all' together"))
|
||||
if cmd.Args().Get(1) != "" && rmAllSecrets {
|
||||
internal.ShowSubcommandHelpAndError(cmd, errors.New("cannot use '<secret-name>' and '--all' together"))
|
||||
}
|
||||
|
||||
if c.Args().Get(1) == "" && !rmAllSecrets {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("no secret(s) specified?"))
|
||||
if cmd.Args().Get(1) == "" && !rmAllSecrets {
|
||||
internal.ShowSubcommandHelpAndError(cmd, errors.New("no secret(s) specified?"))
|
||||
}
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
@ -288,7 +286,7 @@ Example:
|
||||
}
|
||||
|
||||
match := false
|
||||
secretToRm := c.Args().Get(1)
|
||||
secretToRm := cmd.Args().Get(1)
|
||||
for secretName, val := range secrets {
|
||||
secretRemoteName := fmt.Sprintf("%s_%s_%s", app.StackName(), secretName, val.Version)
|
||||
if _, ok := remoteSecretNames[secretRemoteName]; ok {
|
||||
@ -331,11 +329,12 @@ var appSecretLsCommand = cli.Command{
|
||||
internal.ChaosFlag,
|
||||
internal.MachineReadableFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "List all secrets",
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "List all secrets",
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -378,14 +377,15 @@ var appSecretLsCommand = cli.Command{
|
||||
}
|
||||
|
||||
var appSecretCommand = cli.Command{
|
||||
Name: "secret",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "Manage app secrets",
|
||||
ArgsUsage: "<domain>",
|
||||
Subcommands: []cli.Command{
|
||||
appSecretGenerateCommand,
|
||||
appSecretInsertCommand,
|
||||
appSecretRmCommand,
|
||||
appSecretLsCommand,
|
||||
Name: "secret",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "Manage app secrets",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app secret [command] [options] [arguments]",
|
||||
Commands: []*cli.Command{
|
||||
&appSecretGenerateCommand,
|
||||
&appSecretInsertCommand,
|
||||
&appSecretRmCommand,
|
||||
&appSecretLsCommand,
|
||||
},
|
||||
}
|
||||
|
@ -13,21 +13,20 @@ import (
|
||||
"coopcloud.tech/abra/pkg/service"
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
containerTypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var appServicesCommand = cli.Command{
|
||||
Name: "services",
|
||||
Aliases: []string{"sr"},
|
||||
Usage: "Display all services of an app",
|
||||
ArgsUsage: "<domain>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Name: "services",
|
||||
Aliases: []string{"sr"},
|
||||
Usage: "Display all services of an app",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app services [options] <domain>",
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -13,13 +13,14 @@ import (
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
dockerClient "github.com/docker/docker/client"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var prune bool
|
||||
|
||||
var pruneFlag = &cli.BoolFlag{
|
||||
Name: "prune, p",
|
||||
Name: "prune",
|
||||
Aliases: []string{"p"},
|
||||
Destination: &prune,
|
||||
Usage: "Prunes unused containers, networks, and dangling images for an app",
|
||||
}
|
||||
@ -61,26 +62,25 @@ func pruneApp(cl *dockerClient.Client, app appPkg.App) error {
|
||||
}
|
||||
|
||||
var appUndeployCommand = cli.Command{
|
||||
Name: "undeploy",
|
||||
Aliases: []string{"un"},
|
||||
ArgsUsage: "<domain>",
|
||||
Name: "undeploy",
|
||||
Aliases: []string{"un"},
|
||||
UsageText: "abra app undeploy [options] <domain>",
|
||||
HideHelpCommand: true,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
pruneFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Undeploy an app",
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Description: `
|
||||
This does not destroy any of the application data.
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Undeploy an app",
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Description: `This does not destroy any of the application data.
|
||||
|
||||
However, you should remain vigilant, as your swarm installation will consider
|
||||
any previously attached volumes as eligible for pruning once undeployed.
|
||||
|
||||
Passing "-p/--prune" does not remove those volumes.`,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -14,40 +14,33 @@ import (
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"coopcloud.tech/tagcmp"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var appUpgradeCommand = cli.Command{
|
||||
Name: "upgrade",
|
||||
Aliases: []string{"up"},
|
||||
Usage: "Upgrade an app",
|
||||
ArgsUsage: "<domain> [<version>]",
|
||||
UsageText: "abra app upgrade [options] <domain> [<version>]",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.ForceFlag,
|
||||
internal.NoDomainChecksFlag,
|
||||
internal.DontWaitConvergeFlag,
|
||||
internal.OfflineFlag,
|
||||
internal.ReleaseNotesFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
Upgrade an app.
|
||||
Description: `Upgrade an app.
|
||||
|
||||
Unlike "deploy", chaos operations are not supported here. Only recipe versions
|
||||
are supported values for "[<version>]".
|
||||
|
||||
An upgrade can be destructive, please ensure you have a copy of your app data
|
||||
beforehand.
|
||||
|
||||
EXAMPLE:
|
||||
|
||||
abra app upgrade foo.example.com
|
||||
abra app upgrade foo.example.com 1.2.3+3.2.1`,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
beforehand.`,
|
||||
EnableShellCompletion: true,
|
||||
HideHelpCommand: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
stackName := app.StackName()
|
||||
|
||||
if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
@ -85,7 +78,7 @@ EXAMPLE:
|
||||
log.Warnf("failed to determine deployed version of %s", app.Name)
|
||||
}
|
||||
|
||||
specificVersion := c.Args().Get(1)
|
||||
specificVersion := cmd.Args().Get(1)
|
||||
if specificVersion != "" {
|
||||
parsedDeployedVersion, err := tagcmp.Parse(deployMeta.Version)
|
||||
if err != nil {
|
||||
|
@ -10,22 +10,20 @@ import (
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var appVolumeListCommand = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
ArgsUsage: "<domain>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "List volumes associated with an app",
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
UsageText: "abra app volume list [options] <domain>",
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "List volumes associated with an app",
|
||||
HideHelpCommand: true,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
@ -64,27 +62,28 @@ var appVolumeListCommand = cli.Command{
|
||||
var appVolumeRemoveCommand = cli.Command{
|
||||
Name: "remove",
|
||||
Usage: "Remove volume(s) associated with an app",
|
||||
Description: `
|
||||
This command supports removing volumes associated with an app. The app in
|
||||
question must be undeployed before you try to remove volumes. See "abra app
|
||||
undeploy <domain>" for more.
|
||||
Description: `Memove volumes associated with an app.
|
||||
|
||||
The app in question must be undeployed before you try to remove volumes. See
|
||||
"abra app undeploy <domain>" for more.
|
||||
|
||||
The command is interactive and will show a multiple select input which allows
|
||||
you to make a seclection. Use the "?" key to see more help on navigating this
|
||||
interface.
|
||||
|
||||
Passing "--force/-f" will select all volumes for removal. Be careful.`,
|
||||
ArgsUsage: "<domain>",
|
||||
Aliases: []string{"rm"},
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra app volume remove [options] <domain>",
|
||||
Aliases: []string{"rm"},
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.ForceFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.AppNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
app := internal.ValidateApp(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.AppNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
app := internal.ValidateApp(cmd)
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
if err != nil {
|
||||
@ -145,12 +144,13 @@ Passing "--force/-f" will select all volumes for removal. Be careful.`,
|
||||
}
|
||||
|
||||
var appVolumeCommand = cli.Command{
|
||||
Name: "volume",
|
||||
Aliases: []string{"vl"},
|
||||
Usage: "Manage app volumes",
|
||||
ArgsUsage: "<domain>",
|
||||
Subcommands: []cli.Command{
|
||||
appVolumeListCommand,
|
||||
appVolumeRemoveCommand,
|
||||
Name: "volume",
|
||||
Aliases: []string{"vl"},
|
||||
Usage: "Manage app volumes",
|
||||
UsageText: "abra app volume [command] [options] [arguments]",
|
||||
HideHelpCommand: true,
|
||||
Commands: []*cli.Command{
|
||||
&appVolumeListCommand,
|
||||
&appVolumeRemoveCommand,
|
||||
},
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package catalogue
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@ -15,25 +16,23 @@ import (
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var catalogueGenerateCommand = cli.Command{
|
||||
Name: "generate",
|
||||
Aliases: []string{"g"},
|
||||
Usage: "Generate the recipe catalogue",
|
||||
Name: "generate",
|
||||
Aliases: []string{"g"},
|
||||
Usage: "Generate the recipe catalogue",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra catalogue generate [options] [<recipe>]",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.PublishFlag,
|
||||
internal.DryFlag,
|
||||
internal.SkipUpdatesFlag,
|
||||
internal.ChaosFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
Generate a new copy of the recipe catalogue.
|
||||
Description: `Generate a new copy of the recipe catalogue.
|
||||
|
||||
It is possible to generate new metadata for a single recipe by passing
|
||||
<recipe>. The existing local catalogue will be updated, not overwritten.
|
||||
@ -45,14 +44,14 @@ If you have a Hub account you can have Abra log you in to avoid this. Pass
|
||||
Push your new release to git.coopcloud.tech with "-p/--publish". This requires
|
||||
that you have permission to git push to these repositories and have your SSH
|
||||
keys configured on your account.`,
|
||||
ArgsUsage: "[<recipe>]",
|
||||
BashComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
recipeName := c.Args().First()
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
recipeName := cmd.Args().First()
|
||||
r := recipe.Get(recipeName)
|
||||
|
||||
if recipeName != "" {
|
||||
internal.ValidateRecipe(c)
|
||||
internal.ValidateRecipe(cmd)
|
||||
}
|
||||
|
||||
if !internal.Chaos {
|
||||
@ -205,11 +204,12 @@ keys configured on your account.`,
|
||||
|
||||
// CatalogueCommand defines the `abra catalogue` command and sub-commands.
|
||||
var CatalogueCommand = cli.Command{
|
||||
Name: "catalogue",
|
||||
Usage: "Manage the recipe catalogue",
|
||||
Aliases: []string{"c"},
|
||||
ArgsUsage: "<recipe>",
|
||||
Subcommands: []cli.Command{
|
||||
catalogueGenerateCommand,
|
||||
Name: "catalogue",
|
||||
Usage: "Manage the recipe catalogue",
|
||||
Aliases: []string{"c"},
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra catalogue [command] [options] [arguments]",
|
||||
Commands: []*cli.Command{
|
||||
&catalogueGenerateCommand,
|
||||
},
|
||||
}
|
||||
|
96
cli/cli.go
96
cli/cli.go
@ -2,6 +2,7 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@ -18,7 +19,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/web"
|
||||
charmLog "github.com/charmbracelet/log"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// AutoCompleteCommand helps people set up auto-complete in their shells
|
||||
@ -26,23 +27,15 @@ var AutoCompleteCommand = cli.Command{
|
||||
Name: "autocomplete",
|
||||
Aliases: []string{"ac"},
|
||||
Usage: "Configure shell autocompletion",
|
||||
Description: `
|
||||
Set up shell auto-completion.
|
||||
Description: `Set up shell auto-completion.
|
||||
|
||||
Supported shells are: bash, fish, fizsh & zsh.
|
||||
|
||||
EXAMPLE:
|
||||
|
||||
abra autocomplete bash`,
|
||||
Supported shells are: bash, fish, fizsh & zsh.`,
|
||||
ArgsUsage: "<shell>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
shellType := c.Args().First()
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
shellType := cmd.Args().First()
|
||||
|
||||
if shellType == "" {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("no shell provided"))
|
||||
internal.ShowSubcommandHelpAndError(cmd, errors.New("no shell provided"))
|
||||
}
|
||||
|
||||
supportedShells := map[string]bool{
|
||||
@ -113,30 +106,24 @@ var UpgradeCommand = cli.Command{
|
||||
Name: "upgrade",
|
||||
Aliases: []string{"u"},
|
||||
Usage: "Upgrade abra",
|
||||
Description: `
|
||||
Upgrade abra in-place with the latest stable or release candidate.
|
||||
Description: `Upgrade abra in-place with the latest stable or release candidate.
|
||||
|
||||
Use "-r/--rc" to install the latest release candidate. Please bear in mind that
|
||||
it may contain absolutely catastrophic deal-breaker bugs. Thank you very much
|
||||
for the testing efforts 💗
|
||||
|
||||
EXAMPLE:
|
||||
|
||||
abra upgrade
|
||||
abra upgrade --rc`,
|
||||
for the testing efforts 💗`,
|
||||
Flags: []cli.Flag{internal.RCFlag},
|
||||
Action: func(c *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
mainURL := "https://install.abra.coopcloud.tech"
|
||||
cmd := exec.Command("bash", "-c", fmt.Sprintf("wget -q -O- %s | bash", mainURL))
|
||||
c := exec.Command("bash", "-c", fmt.Sprintf("wget -q -O- %s | bash", mainURL))
|
||||
|
||||
if internal.RC {
|
||||
releaseCandidateURL := "https://git.coopcloud.tech/coop-cloud/abra/raw/branch/main/scripts/installer/installer"
|
||||
cmd = exec.Command("bash", "-c", fmt.Sprintf("wget -q -O- %s | bash -s -- --rc", releaseCandidateURL))
|
||||
c = exec.Command("bash", "-c", fmt.Sprintf("wget -q -O- %s | bash -s -- --rc", releaseCandidateURL))
|
||||
}
|
||||
|
||||
log.Debugf("attempting to run %s", cmd)
|
||||
log.Debugf("attempting to run %s", c)
|
||||
|
||||
if err := internal.RunCmd(cmd); err != nil {
|
||||
if err := internal.RunCmd(c); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@ -144,32 +131,32 @@ EXAMPLE:
|
||||
},
|
||||
}
|
||||
|
||||
func newAbraApp(version, commit string) *cli.App {
|
||||
app := &cli.App{
|
||||
Name: "abra",
|
||||
Usage: `the Co-op Cloud command-line utility belt 🎩🐇
|
||||
____ ____ _ _
|
||||
/ ___|___ ___ _ __ / ___| | ___ _ _ __| |
|
||||
| | / _ \ _____ / _ \| '_ \ | | | |/ _ \| | | |/ _' |
|
||||
| |__| (_) |_____| (_) | |_) | | |___| | (_) | |_| | (_| |
|
||||
\____\___/ \___/| .__/ \____|_|\___/ \__,_|\__,_|
|
||||
|_|
|
||||
`,
|
||||
Version: fmt.Sprintf("%s-%s", version, commit[:7]),
|
||||
Commands: []cli.Command{
|
||||
app.AppCommand,
|
||||
server.ServerCommand,
|
||||
recipe.RecipeCommand,
|
||||
catalogue.CatalogueCommand,
|
||||
UpgradeCommand,
|
||||
AutoCompleteCommand,
|
||||
func newAbraApp(version, commit string) *cli.Command {
|
||||
app := &cli.Command{
|
||||
Name: "abra",
|
||||
Usage: "The Co-op Cloud command-line utility belt 🎩🐇",
|
||||
UsageText: "abra [command] [options] [arguments]",
|
||||
Version: fmt.Sprintf("%s-%s", version, commit[:7]),
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
internal.NoInputFlag,
|
||||
},
|
||||
BashComplete: autocomplete.SubcommandComplete,
|
||||
Commands: []*cli.Command{
|
||||
&app.AppCommand,
|
||||
&server.ServerCommand,
|
||||
&recipe.RecipeCommand,
|
||||
&catalogue.CatalogueCommand,
|
||||
&UpgradeCommand,
|
||||
&AutoCompleteCommand,
|
||||
},
|
||||
EnableShellCompletion: true,
|
||||
UseShortOptionHandling: true,
|
||||
HideHelpCommand: true,
|
||||
ShellComplete: autocomplete.SubcommandComplete,
|
||||
}
|
||||
|
||||
app.EnableBashCompletion = true
|
||||
|
||||
app.Before = func(c *cli.Context) error {
|
||||
app.Before = func(ctx context.Context, cmd *cli.Command) error {
|
||||
paths := []string{
|
||||
config.ABRA_DIR,
|
||||
config.SERVERS_DIR,
|
||||
@ -193,6 +180,13 @@ func newAbraApp(version, commit string) *cli.App {
|
||||
return nil
|
||||
}
|
||||
|
||||
cli.HelpFlag = &cli.BoolFlag{
|
||||
Name: "help",
|
||||
Aliases: []string{"h, H"},
|
||||
Usage: "Show help",
|
||||
Persistent: true,
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
@ -200,7 +194,7 @@ func newAbraApp(version, commit string) *cli.App {
|
||||
func RunApp(version, commit string) {
|
||||
app := newAbraApp(version, commit)
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
if err := app.Run(context.Background(), os.Args); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Secrets stores the variable from SecretsFlag
|
||||
@ -12,7 +13,8 @@ var Secrets bool
|
||||
|
||||
// SecretsFlag turns on/off automatically generating secrets
|
||||
var SecretsFlag = &cli.BoolFlag{
|
||||
Name: "secrets, S",
|
||||
Name: "secrets",
|
||||
Aliases: []string{"S"},
|
||||
Usage: "Automatically generate secrets",
|
||||
Destination: &Secrets,
|
||||
}
|
||||
@ -22,7 +24,8 @@ var Pass bool
|
||||
|
||||
// PassFlag turns on/off storing generated secrets in pass
|
||||
var PassFlag = &cli.BoolFlag{
|
||||
Name: "pass, p",
|
||||
Name: "pass",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Store the generated secrets in a local pass store",
|
||||
Destination: &Pass,
|
||||
}
|
||||
@ -32,21 +35,24 @@ var PassRemove bool
|
||||
|
||||
// PassRemoveFlag turns on/off removing generated secrets from pass
|
||||
var PassRemoveFlag = &cli.BoolFlag{
|
||||
Name: "pass, p",
|
||||
Name: "pass",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Remove generated secrets from a local pass store",
|
||||
Destination: &PassRemove,
|
||||
}
|
||||
|
||||
var File bool
|
||||
var FileFlag = &cli.BoolFlag{
|
||||
Name: "file, f",
|
||||
Name: "file",
|
||||
Aliases: []string{"f"},
|
||||
Usage: "Treat input as a file",
|
||||
Destination: &File,
|
||||
}
|
||||
|
||||
var Trim bool
|
||||
var TrimFlag = &cli.BoolFlag{
|
||||
Name: "trim, t",
|
||||
Name: "trim",
|
||||
Aliases: []string{"t"},
|
||||
Usage: "Trim input",
|
||||
Destination: &Trim,
|
||||
}
|
||||
@ -56,7 +62,8 @@ var Force bool
|
||||
|
||||
// ForceFlag turns on/off force functionality.
|
||||
var ForceFlag = &cli.BoolFlag{
|
||||
Name: "force, f",
|
||||
Name: "force",
|
||||
Aliases: []string{"f"},
|
||||
Usage: "Perform action without further prompt. Use with care!",
|
||||
Destination: &Force,
|
||||
}
|
||||
@ -66,7 +73,8 @@ var Chaos bool
|
||||
|
||||
// ChaosFlag turns on/off chaos functionality.
|
||||
var ChaosFlag = &cli.BoolFlag{
|
||||
Name: "chaos, C",
|
||||
Name: "chaos",
|
||||
Aliases: []string{"C"},
|
||||
Usage: "Proceed with uncommitted recipes changes. Use with care!",
|
||||
Destination: &Chaos,
|
||||
}
|
||||
@ -76,16 +84,19 @@ var Tty bool
|
||||
|
||||
// TtyFlag turns on/off tty mode.
|
||||
var TtyFlag = &cli.BoolFlag{
|
||||
Name: "tty, T",
|
||||
Name: "tty",
|
||||
Aliases: []string{"T"},
|
||||
Usage: "Disables TTY mode to run this command from a script.",
|
||||
Destination: &Tty,
|
||||
}
|
||||
|
||||
var NoInput bool
|
||||
var NoInputFlag = &cli.BoolFlag{
|
||||
Name: "no-input, n",
|
||||
Name: "no-input",
|
||||
Aliases: []string{"n"},
|
||||
Usage: "Toggle non-interactive mode",
|
||||
Destination: &NoInput,
|
||||
Persistent: true,
|
||||
}
|
||||
|
||||
// Debug stores the variable from DebugFlag.
|
||||
@ -93,8 +104,10 @@ var Debug bool
|
||||
|
||||
// DebugFlag turns on/off verbose logging down to the DEBUG level.
|
||||
var DebugFlag = &cli.BoolFlag{
|
||||
Name: "debug, d",
|
||||
Name: "debug",
|
||||
Aliases: []string{"d"},
|
||||
Destination: &Debug,
|
||||
Persistent: true,
|
||||
Usage: "Show DEBUG messages",
|
||||
}
|
||||
|
||||
@ -103,9 +116,11 @@ var Offline bool
|
||||
|
||||
// DebugFlag turns on/off offline mode.
|
||||
var OfflineFlag = &cli.BoolFlag{
|
||||
Name: "offline, o",
|
||||
Name: "offline",
|
||||
Aliases: []string{"o"},
|
||||
Destination: &Offline,
|
||||
Usage: "Prefer offline & filesystem access when possible",
|
||||
Persistent: true,
|
||||
}
|
||||
|
||||
// ReleaseNotes stores the variable from ReleaseNotesFlag.
|
||||
@ -113,7 +128,8 @@ var ReleaseNotes bool
|
||||
|
||||
// ReleaseNotesFlag turns on/off printing only release notes when upgrading.
|
||||
var ReleaseNotesFlag = &cli.BoolFlag{
|
||||
Name: "releasenotes, r",
|
||||
Name: "releasenotes",
|
||||
Aliases: []string{"r"},
|
||||
Destination: &ReleaseNotes,
|
||||
Usage: "Only show release notes",
|
||||
}
|
||||
@ -123,7 +139,8 @@ var MachineReadable bool
|
||||
|
||||
// MachineReadableFlag turns on/off machine readable output where supported
|
||||
var MachineReadableFlag = &cli.BoolFlag{
|
||||
Name: "machine, m",
|
||||
Name: "machine",
|
||||
Aliases: []string{"m"},
|
||||
Destination: &MachineReadable,
|
||||
Usage: "Output in a machine-readable format (where supported)",
|
||||
}
|
||||
@ -133,49 +150,56 @@ var RC bool
|
||||
|
||||
// RCFlag chooses the latest release candidate for install
|
||||
var RCFlag = &cli.BoolFlag{
|
||||
Name: "rc, r",
|
||||
Name: "rc",
|
||||
Aliases: []string{"r"},
|
||||
Destination: &RC,
|
||||
Usage: "Install the latest release candidate",
|
||||
}
|
||||
|
||||
var Major bool
|
||||
var MajorFlag = &cli.BoolFlag{
|
||||
Name: "major, x",
|
||||
Name: "major",
|
||||
Aliases: []string{"x"},
|
||||
Usage: "Increase the major part of the version",
|
||||
Destination: &Major,
|
||||
}
|
||||
|
||||
var Minor bool
|
||||
var MinorFlag = &cli.BoolFlag{
|
||||
Name: "minor, y",
|
||||
Name: "minor",
|
||||
Aliases: []string{"y"},
|
||||
Usage: "Increase the minor part of the version",
|
||||
Destination: &Minor,
|
||||
}
|
||||
|
||||
var Patch bool
|
||||
var PatchFlag = &cli.BoolFlag{
|
||||
Name: "patch, z",
|
||||
Name: "patch",
|
||||
Aliases: []string{"z"},
|
||||
Usage: "Increase the patch part of the version",
|
||||
Destination: &Patch,
|
||||
}
|
||||
|
||||
var Dry bool
|
||||
var DryFlag = &cli.BoolFlag{
|
||||
Name: "dry-run, r",
|
||||
Name: "dry-run",
|
||||
Aliases: []string{"r"},
|
||||
Usage: "Only reports changes that would be made",
|
||||
Destination: &Dry,
|
||||
}
|
||||
|
||||
var Publish bool
|
||||
var PublishFlag = &cli.BoolFlag{
|
||||
Name: "publish, p",
|
||||
Name: "publish",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Publish changes to git.coopcloud.tech",
|
||||
Destination: &Publish,
|
||||
}
|
||||
|
||||
var Domain string
|
||||
var DomainFlag = &cli.StringFlag{
|
||||
Name: "domain, D",
|
||||
Name: "domain",
|
||||
Aliases: []string{"D"},
|
||||
Value: "",
|
||||
Usage: "Choose a domain name",
|
||||
Destination: &Domain,
|
||||
@ -183,7 +207,8 @@ var DomainFlag = &cli.StringFlag{
|
||||
|
||||
var NewAppServer string
|
||||
var NewAppServerFlag = &cli.StringFlag{
|
||||
Name: "server, s",
|
||||
Name: "server",
|
||||
Aliases: []string{"s"},
|
||||
Value: "",
|
||||
Usage: "Show apps of a specific server",
|
||||
Destination: &NewAppServer,
|
||||
@ -191,21 +216,24 @@ var NewAppServerFlag = &cli.StringFlag{
|
||||
|
||||
var NoDomainChecks bool
|
||||
var NoDomainChecksFlag = &cli.BoolFlag{
|
||||
Name: "no-domain-checks, D",
|
||||
Name: "no-domain-checks",
|
||||
Aliases: []string{"D"},
|
||||
Usage: "Disable public DNS checks",
|
||||
Destination: &NoDomainChecks,
|
||||
}
|
||||
|
||||
var StdErrOnly bool
|
||||
var StdErrOnlyFlag = &cli.BoolFlag{
|
||||
Name: "stderr, s",
|
||||
Name: "stderr",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "Only tail stderr",
|
||||
Destination: &StdErrOnly,
|
||||
}
|
||||
|
||||
var SinceLogs string
|
||||
var SinceLogsFlag = &cli.StringFlag{
|
||||
Name: "since, S",
|
||||
Name: "since",
|
||||
Aliases: []string{"S"},
|
||||
Value: "",
|
||||
Usage: "tail logs since YYYY-MM-DDTHH:MM:SSZ",
|
||||
Destination: &SinceLogs,
|
||||
@ -213,49 +241,56 @@ var SinceLogsFlag = &cli.StringFlag{
|
||||
|
||||
var DontWaitConverge bool
|
||||
var DontWaitConvergeFlag = &cli.BoolFlag{
|
||||
Name: "no-converge-checks, c",
|
||||
Name: "no-converge-checks",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Don't wait for converge logic checks",
|
||||
Destination: &DontWaitConverge,
|
||||
}
|
||||
|
||||
var Watch bool
|
||||
var WatchFlag = &cli.BoolFlag{
|
||||
Name: "watch, w",
|
||||
Name: "watch",
|
||||
Aliases: []string{"w"},
|
||||
Usage: "Watch status by polling repeatedly",
|
||||
Destination: &Watch,
|
||||
}
|
||||
|
||||
var OnlyErrors bool
|
||||
var OnlyErrorFlag = &cli.BoolFlag{
|
||||
Name: "errors, e",
|
||||
Name: "errors",
|
||||
Aliases: []string{"e"},
|
||||
Usage: "Only show errors",
|
||||
Destination: &OnlyErrors,
|
||||
}
|
||||
|
||||
var SkipUpdates bool
|
||||
var SkipUpdatesFlag = &cli.BoolFlag{
|
||||
Name: "skip-updates, s",
|
||||
Name: "skip-updates",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "Skip updating recipe repositories",
|
||||
Destination: &SkipUpdates,
|
||||
}
|
||||
|
||||
var AllTags bool
|
||||
var AllTagsFlag = &cli.BoolFlag{
|
||||
Name: "all-tags, a",
|
||||
Name: "all-tags",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "List all tags, not just upgrades",
|
||||
Destination: &AllTags,
|
||||
}
|
||||
|
||||
var LocalCmd bool
|
||||
var LocalCmdFlag = &cli.BoolFlag{
|
||||
Name: "local, l",
|
||||
Name: "local",
|
||||
Aliases: []string{"l"},
|
||||
Usage: "Run command locally",
|
||||
Destination: &LocalCmd,
|
||||
}
|
||||
|
||||
var RemoteUser string
|
||||
var RemoteUserFlag = &cli.StringFlag{
|
||||
Name: "user, u",
|
||||
Name: "user",
|
||||
Aliases: []string{"u"},
|
||||
Value: "",
|
||||
Usage: "User to run command within a service context",
|
||||
Destination: &RemoteUser,
|
||||
@ -263,7 +298,8 @@ var RemoteUserFlag = &cli.StringFlag{
|
||||
|
||||
var GitName string
|
||||
var GitNameFlag = &cli.StringFlag{
|
||||
Name: "git-name, gn",
|
||||
Name: "git-name",
|
||||
Aliases: []string{"gn"},
|
||||
Value: "",
|
||||
Usage: "Git (user) name to do commits with",
|
||||
Destination: &GitName,
|
||||
@ -271,7 +307,8 @@ var GitNameFlag = &cli.StringFlag{
|
||||
|
||||
var GitEmail string
|
||||
var GitEmailFlag = &cli.StringFlag{
|
||||
Name: "git-email, ge",
|
||||
Name: "git-email",
|
||||
Aliases: []string{"ge"},
|
||||
Value: "",
|
||||
Usage: "Git email name to do commits with",
|
||||
Destination: &GitEmail,
|
||||
@ -279,13 +316,14 @@ var GitEmailFlag = &cli.StringFlag{
|
||||
|
||||
var AllServices bool
|
||||
var AllServicesFlag = &cli.BoolFlag{
|
||||
Name: "all-services, a",
|
||||
Name: "all-services",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Restart all services",
|
||||
Destination: &AllServices,
|
||||
}
|
||||
|
||||
// SubCommandBefore wires up pre-action machinery (e.g. --debug handling).
|
||||
func SubCommandBefore(c *cli.Context) error {
|
||||
func SubCommandBefore(ctx context.Context, cmd *cli.Command) error {
|
||||
if Debug {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetOutput(os.Stderr)
|
||||
|
@ -4,13 +4,13 @@ import (
|
||||
"os"
|
||||
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// ShowSubcommandHelpAndError exits the program on error, logs the error to the
|
||||
// terminal, and shows the help command.
|
||||
func ShowSubcommandHelpAndError(c *cli.Context, err interface{}) {
|
||||
if err2 := cli.ShowSubcommandHelp(c); err2 != nil {
|
||||
func ShowSubcommandHelpAndError(cmd *cli.Command, err interface{}) {
|
||||
if err2 := cli.ShowSubcommandHelp(cmd); err2 != nil {
|
||||
log.Error(err2)
|
||||
}
|
||||
log.Error(err)
|
||||
|
@ -9,12 +9,12 @@ import (
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// ValidateRecipe ensures the recipe arg is valid.
|
||||
func ValidateRecipe(c *cli.Context) recipe.Recipe {
|
||||
recipeName := c.Args().First()
|
||||
func ValidateRecipe(cmd *cli.Command) recipe.Recipe {
|
||||
recipeName := cmd.Args().First()
|
||||
|
||||
if recipeName == "" && !NoInput {
|
||||
var recipes []string
|
||||
@ -54,7 +54,7 @@ func ValidateRecipe(c *cli.Context) recipe.Recipe {
|
||||
}
|
||||
|
||||
if recipeName == "" {
|
||||
ShowSubcommandHelpAndError(c, errors.New("no recipe name provided"))
|
||||
ShowSubcommandHelpAndError(cmd, errors.New("no recipe name provided"))
|
||||
}
|
||||
|
||||
chosenRecipe := recipe.Get(recipeName)
|
||||
@ -64,7 +64,7 @@ func ValidateRecipe(c *cli.Context) recipe.Recipe {
|
||||
}
|
||||
_, err = chosenRecipe.GetComposeConfig(nil)
|
||||
if err != nil {
|
||||
if c.Command.Name == "generate" {
|
||||
if cmd.Name == "generate" {
|
||||
if strings.Contains(err.Error(), "missing a compose") {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -83,11 +83,11 @@ func ValidateRecipe(c *cli.Context) recipe.Recipe {
|
||||
}
|
||||
|
||||
// ValidateApp ensures the app name arg is valid.
|
||||
func ValidateApp(c *cli.Context) app.App {
|
||||
appName := c.Args().First()
|
||||
func ValidateApp(cmd *cli.Command) app.App {
|
||||
appName := cmd.Args().First()
|
||||
|
||||
if appName == "" {
|
||||
ShowSubcommandHelpAndError(c, errors.New("no app provided"))
|
||||
ShowSubcommandHelpAndError(cmd, errors.New("no app provided"))
|
||||
}
|
||||
|
||||
app, err := app.Get(appName)
|
||||
@ -101,8 +101,8 @@ func ValidateApp(c *cli.Context) app.App {
|
||||
}
|
||||
|
||||
// ValidateDomain ensures the domain name arg is valid.
|
||||
func ValidateDomain(c *cli.Context) string {
|
||||
domainName := c.Args().First()
|
||||
func ValidateDomain(cmd *cli.Command) string {
|
||||
domainName := cmd.Args().First()
|
||||
|
||||
if domainName == "" && !NoInput {
|
||||
prompt := &survey.Input{
|
||||
@ -115,7 +115,7 @@ func ValidateDomain(c *cli.Context) string {
|
||||
}
|
||||
|
||||
if domainName == "" {
|
||||
ShowSubcommandHelpAndError(c, errors.New("no domain provided"))
|
||||
ShowSubcommandHelpAndError(cmd, errors.New("no domain provided"))
|
||||
}
|
||||
|
||||
log.Debugf("validated %s as domain argument", domainName)
|
||||
@ -124,10 +124,10 @@ func ValidateDomain(c *cli.Context) string {
|
||||
}
|
||||
|
||||
// ValidateSubCmdFlags ensures flag order conforms to correct order
|
||||
func ValidateSubCmdFlags(c *cli.Context) bool {
|
||||
for argIdx, arg := range c.Args() {
|
||||
func ValidateSubCmdFlags(cmd *cli.Command) bool {
|
||||
for argIdx, arg := range cmd.Args().Slice() {
|
||||
if !strings.HasPrefix(arg, "--") {
|
||||
for _, flag := range c.Args()[argIdx:] {
|
||||
for _, flag := range cmd.Args().Slice()[argIdx:] {
|
||||
if strings.HasPrefix(flag, "--") {
|
||||
return false
|
||||
}
|
||||
@ -138,8 +138,8 @@ func ValidateSubCmdFlags(c *cli.Context) bool {
|
||||
}
|
||||
|
||||
// ValidateServer ensures the server name arg is valid.
|
||||
func ValidateServer(c *cli.Context) string {
|
||||
serverName := c.Args().First()
|
||||
func ValidateServer(cmd *cli.Command) string {
|
||||
serverName := cmd.Args().First()
|
||||
|
||||
serverNames, err := config.ReadServerNames()
|
||||
if err != nil {
|
||||
@ -164,11 +164,11 @@ func ValidateServer(c *cli.Context) string {
|
||||
}
|
||||
|
||||
if serverName == "" {
|
||||
ShowSubcommandHelpAndError(c, errors.New("no server provided"))
|
||||
ShowSubcommandHelpAndError(cmd, errors.New("no server provided"))
|
||||
}
|
||||
|
||||
if !matched {
|
||||
ShowSubcommandHelpAndError(c, errors.New("server doesn't exist?"))
|
||||
ShowSubcommandHelpAndError(cmd, errors.New("server doesn't exist?"))
|
||||
}
|
||||
|
||||
log.Debugf("validated %s as server argument", serverName)
|
||||
|
@ -1,27 +1,27 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
gitPkg "coopcloud.tech/abra/pkg/git"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var recipeDiffCommand = cli.Command{
|
||||
Name: "diff",
|
||||
Usage: "Show unstaged changes in recipe config",
|
||||
Description: "This command requires /usr/bin/git.",
|
||||
Aliases: []string{"d"},
|
||||
ArgsUsage: "<recipe>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
r := internal.ValidateRecipe(c)
|
||||
Name: "diff",
|
||||
Usage: "Show unstaged changes in recipe config",
|
||||
Description: "This command requires /usr/bin/git.",
|
||||
HideHelpCommand: true,
|
||||
Aliases: []string{"d"},
|
||||
UsageText: "abra recipe diff [options] <recipe>",
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
r := internal.ValidateRecipe(cmd)
|
||||
|
||||
if err := gitPkg.DiffUnstaged(r.Dir); err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -1,32 +1,30 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var recipeFetchCommand = cli.Command{
|
||||
Name: "fetch",
|
||||
Usage: "Fetch recipe(s)",
|
||||
Aliases: []string{"f"},
|
||||
ArgsUsage: "[<recipe>]",
|
||||
Description: "Retrieves all recipes if no <recipe> argument is passed",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
recipeName := c.Args().First()
|
||||
Name: "fetch",
|
||||
Usage: "Fetch recipe(s)",
|
||||
Aliases: []string{"f"},
|
||||
UsageText: "abra recipe fetch [options] [<recipe>]",
|
||||
Description: "Retrieves all recipes if no <recipe> argument is passed",
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
recipeName := cmd.Args().First()
|
||||
r := recipe.Get(recipeName)
|
||||
if recipeName != "" {
|
||||
internal.ValidateRecipe(c)
|
||||
internal.ValidateRecipe(cmd)
|
||||
if err := r.Ensure(false, false); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
@ -8,25 +9,24 @@ import (
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/lint"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var recipeLintCommand = cli.Command{
|
||||
Name: "lint",
|
||||
Usage: "Lint a recipe",
|
||||
Aliases: []string{"l"},
|
||||
ArgsUsage: "<recipe>",
|
||||
Name: "lint",
|
||||
Usage: "Lint a recipe",
|
||||
Aliases: []string{"l"},
|
||||
UsageText: "abra recipe lint [options] <recipe>",
|
||||
HideHelpCommand: true,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OnlyErrorFlag,
|
||||
internal.OfflineFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.ChaosFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
recipe := internal.ValidateRecipe(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
recipe := internal.ValidateRecipe(cmd)
|
||||
|
||||
if err := recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
@ -10,29 +11,30 @@ import (
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var pattern string
|
||||
var patternFlag = &cli.StringFlag{
|
||||
Name: "pattern, p",
|
||||
Name: "pattern",
|
||||
Aliases: []string{"p"},
|
||||
Value: "",
|
||||
Usage: "Simple string to filter recipes",
|
||||
Destination: &pattern,
|
||||
}
|
||||
|
||||
var recipeListCommand = cli.Command{
|
||||
Name: "list",
|
||||
Usage: "List available recipes",
|
||||
Aliases: []string{"ls"},
|
||||
Name: "list",
|
||||
Usage: "List recipes",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra recipe list [options]",
|
||||
Aliases: []string{"ls"},
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.MachineReadableFlag,
|
||||
patternFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
catl, err := recipe.ReadRecipeCatalogue(internal.Offline)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
|
@ -2,6 +2,7 @@ package recipe
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@ -13,7 +14,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/git"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// recipeMetadata is the recipe metadata for the README.md
|
||||
@ -34,27 +35,24 @@ var recipeNewCommand = cli.Command{
|
||||
Name: "new",
|
||||
Aliases: []string{"n"},
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.OfflineFlag,
|
||||
internal.GitNameFlag,
|
||||
internal.GitEmailFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Create a new recipe",
|
||||
ArgsUsage: "<recipe>",
|
||||
Description: `
|
||||
Create a new recipe.
|
||||
Before: internal.SubCommandBefore,
|
||||
Usage: "Create a new recipe",
|
||||
UsageText: "abra recipe new [options] <recipe>",
|
||||
HideHelpCommand: true,
|
||||
Description: `Create a new recipe.
|
||||
|
||||
Abra uses the built-in example repository which is available here:
|
||||
|
||||
https://git.coopcloud.tech/coop-cloud/example`,
|
||||
Action: func(c *cli.Context) error {
|
||||
recipeName := c.Args().First()
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
recipeName := cmd.Args().First()
|
||||
r := recipe.Get(recipeName)
|
||||
|
||||
if recipeName == "" {
|
||||
internal.ShowSubcommandHelpAndError(c, errors.New("no recipe name provided"))
|
||||
internal.ShowSubcommandHelpAndError(cmd, errors.New("no recipe name provided"))
|
||||
}
|
||||
|
||||
if _, err := os.Stat(r.Dir); !os.IsNotExist(err) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// RecipeCommand defines all recipe related sub-commands.
|
||||
@ -9,9 +9,8 @@ var RecipeCommand = cli.Command{
|
||||
Name: "recipe",
|
||||
Aliases: []string{"r"},
|
||||
Usage: "Manage recipes",
|
||||
ArgsUsage: "<recipe>",
|
||||
Description: `
|
||||
A recipe is a blueprint for an app. It is a bunch of config files which
|
||||
UsageText: "abra recipe [command] [options] [arguments]",
|
||||
Description: `A recipe is a blueprint for an app. It is a bunch of config files which
|
||||
describe how to deploy and maintain an app. Recipes are maintained by the Co-op
|
||||
Cloud community and you can use Abra to read them, deploy them and create apps
|
||||
for you.
|
||||
@ -19,16 +18,17 @@ for you.
|
||||
Anyone who uses a recipe can become a maintainer. Maintainers typically make
|
||||
sure the recipe is in good working order and the config upgraded in a timely
|
||||
manner.`,
|
||||
Subcommands: []cli.Command{
|
||||
recipeFetchCommand,
|
||||
recipeLintCommand,
|
||||
recipeListCommand,
|
||||
recipeNewCommand,
|
||||
recipeReleaseCommand,
|
||||
recipeSyncCommand,
|
||||
recipeUpgradeCommand,
|
||||
recipeVersionCommand,
|
||||
recipeResetCommand,
|
||||
recipeDiffCommand,
|
||||
HideHelpCommand: true,
|
||||
Commands: []*cli.Command{
|
||||
&recipeFetchCommand,
|
||||
&recipeLintCommand,
|
||||
&recipeListCommand,
|
||||
&recipeNewCommand,
|
||||
&recipeReleaseCommand,
|
||||
&recipeSyncCommand,
|
||||
&recipeUpgradeCommand,
|
||||
&recipeVersionCommand,
|
||||
&recipeResetCommand,
|
||||
&recipeDiffCommand,
|
||||
},
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@ -18,17 +19,19 @@ import (
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var recipeReleaseCommand = cli.Command{
|
||||
Name: "release",
|
||||
Aliases: []string{"rl"},
|
||||
Usage: "Release a new recipe version",
|
||||
ArgsUsage: "<recipe> [<version>]",
|
||||
Description: `
|
||||
Create a new version of a recipe. These versions are then published on the
|
||||
Co-op Cloud recipe catalogue. These versions take the following form:
|
||||
Name: "release",
|
||||
Aliases: []string{"rl"},
|
||||
Usage: "Release a new recipe version",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra recipe release [options] <recipe> [<version>]",
|
||||
Description: `Create a new version of a recipe.
|
||||
|
||||
These versions are then published on the Co-op Cloud recipe catalogue. These
|
||||
versions take the following form:
|
||||
|
||||
a.b.c+x.y.z
|
||||
|
||||
@ -46,19 +49,17 @@ Publish your new release to git.coopcloud.tech with "-p/--publish". This
|
||||
requires that you have permission to git push to these repositories and have
|
||||
your SSH keys configured on your account.`,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.DryFlag,
|
||||
internal.MajorFlag,
|
||||
internal.MinorFlag,
|
||||
internal.PatchFlag,
|
||||
internal.PublishFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
recipe := internal.ValidateRecipe(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
recipe := internal.ValidateRecipe(cmd)
|
||||
|
||||
imagesTmp, err := getImageVersions(recipe)
|
||||
if err != nil {
|
||||
@ -75,7 +76,7 @@ your SSH keys configured on your account.`,
|
||||
log.Fatalf("main app service version for %s is empty?", recipe.Name)
|
||||
}
|
||||
|
||||
tagString := c.Args().Get(1)
|
||||
tagString := cmd.Args().Get(1)
|
||||
if tagString != "" {
|
||||
if _, err := tagcmp.Parse(tagString); err != nil {
|
||||
log.Fatalf("cannot parse %s, invalid tag specified?", tagString)
|
||||
|
@ -1,32 +1,32 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var recipeResetCommand = cli.Command{
|
||||
Name: "reset",
|
||||
Usage: "Remove all unstaged changes from recipe config",
|
||||
Description: "WARNING: this will delete your changes. Be Careful.",
|
||||
Aliases: []string{"rs"},
|
||||
ArgsUsage: "<recipe>",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
recipeName := c.Args().First()
|
||||
Name: "reset",
|
||||
Usage: "Remove all unstaged changes from recipe config",
|
||||
Description: "WARNING: this will delete your changes. Be Careful.",
|
||||
HideHelpCommand: true,
|
||||
Aliases: []string{"rs"},
|
||||
UsageText: "abra recipe reset [options] <recipe>",
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
recipeName := cmd.Args().First()
|
||||
r := recipe.Get(recipeName)
|
||||
|
||||
if recipeName != "" {
|
||||
internal.ValidateRecipe(c)
|
||||
internal.ValidateRecipe(cmd)
|
||||
}
|
||||
|
||||
repo, err := git.PlainOpen(r.Dir)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
@ -12,35 +13,35 @@ import (
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var recipeSyncCommand = cli.Command{
|
||||
Name: "sync",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "Sync recipe version label",
|
||||
ArgsUsage: "<recipe> [<version>]",
|
||||
Name: "sync",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "Sync recipe version label",
|
||||
HideHelpCommand: true,
|
||||
UsageText: "abra recipe lint [options] <recipe> [<version>]",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.DryFlag,
|
||||
internal.MajorFlag,
|
||||
internal.MinorFlag,
|
||||
internal.PatchFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
Generate labels for the main recipe service (i.e. by convention, the service
|
||||
named "app") which corresponds to the following format:
|
||||
Description: `Generate labels for the main recipe service.
|
||||
|
||||
By convention, the service named "app" using the following format:
|
||||
|
||||
coop-cloud.${STACK_NAME}.version=<version>
|
||||
|
||||
Where <version> can be specifed on the command-line or Abra can attempt to
|
||||
auto-generate it for you. The <recipe> configuration will be updated on the
|
||||
local file system.`,
|
||||
BashComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
recipe := internal.ValidateRecipe(c)
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
recipe := internal.ValidateRecipe(cmd)
|
||||
|
||||
mainApp, err := internal.GetMainAppImage(recipe)
|
||||
if err != nil {
|
||||
@ -59,7 +60,7 @@ local file system.`,
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
nextTag := c.Args().Get(1)
|
||||
nextTag := cmd.Args().Get(1)
|
||||
if len(tags) == 0 && nextTag == "" {
|
||||
log.Warnf("no git tags found for %s", recipe.Name)
|
||||
if internal.NoInput {
|
||||
|
@ -2,6 +2,7 @@ package recipe
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
@ -19,7 +20,7 @@ import (
|
||||
"coopcloud.tech/tagcmp"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
type imgPin struct {
|
||||
@ -27,8 +28,8 @@ type imgPin struct {
|
||||
version tagcmp.Tag
|
||||
}
|
||||
|
||||
// anUpgrade represents a single service upgrade (as within a recipe), and the list of tags that it can be upgraded to,
|
||||
// for serialization purposes.
|
||||
// anUpgrade represents a single service upgrade (as within a recipe), and the
|
||||
// list of tags that it can be upgraded to, for serialization purposes.
|
||||
type anUpgrade struct {
|
||||
Service string `json:"service"`
|
||||
Image string `json:"image"`
|
||||
@ -37,13 +38,13 @@ type anUpgrade struct {
|
||||
}
|
||||
|
||||
var recipeUpgradeCommand = cli.Command{
|
||||
Name: "upgrade",
|
||||
Aliases: []string{"u"},
|
||||
Usage: "Upgrade recipe image tags",
|
||||
Description: `
|
||||
Parse all image tags within the given <recipe> configuration and prompt with
|
||||
more recent tags to upgrade to. It will update the relevant compose file tags
|
||||
on the local file system.
|
||||
Name: "upgrade",
|
||||
Aliases: []string{"u"},
|
||||
Usage: "Upgrade recipe image tags",
|
||||
HideHelpCommand: true,
|
||||
Description: `Upgrade a given <recipe> configuration.
|
||||
|
||||
It will update the relevant compose file tags on the local file system.
|
||||
|
||||
Some image tags cannot be parsed because they do not follow some sort of
|
||||
semver-like convention. In this case, all possible tags will be listed and it
|
||||
@ -53,25 +54,20 @@ The command is interactive and will show a select input which allows you to
|
||||
make a seclection. Use the "?" key to see more help on navigating this
|
||||
interface.
|
||||
|
||||
You may invoke this command in "wizard" mode and be prompted for input.
|
||||
|
||||
EXAMPLE:
|
||||
|
||||
abra recipe upgrade`,
|
||||
ArgsUsage: "<recipe>",
|
||||
You may invoke this command in "wizard" mode and be prompted for input.`,
|
||||
UsageText: "abra recipe upgrade [options] [<recipe>]",
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.PatchFlag,
|
||||
internal.MinorFlag,
|
||||
internal.MajorFlag,
|
||||
internal.MachineReadableFlag,
|
||||
internal.AllTagsFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
recipe := internal.ValidateRecipe(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
recipe := internal.ValidateRecipe(cmd)
|
||||
|
||||
if err := recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
@ -10,7 +11,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
recipePkg "coopcloud.tech/abra/pkg/recipe"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func sortServiceByName(versions [][]string) func(i, j int) bool {
|
||||
@ -24,20 +25,19 @@ func sortServiceByName(versions [][]string) func(i, j int) bool {
|
||||
}
|
||||
|
||||
var recipeVersionCommand = cli.Command{
|
||||
Name: "versions",
|
||||
Aliases: []string{"v"},
|
||||
Usage: "List recipe versions",
|
||||
ArgsUsage: "<recipe>",
|
||||
Name: "versions",
|
||||
Aliases: []string{"v"},
|
||||
Usage: "List recipe versions",
|
||||
UsageText: "abra recipe version [options] <recipe>",
|
||||
HideHelpCommand: true,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.MachineReadableFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
recipe := internal.ValidateRecipe(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.RecipeNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
recipe := internal.ValidateRecipe(cmd)
|
||||
|
||||
catl, err := recipePkg.ReadRecipeCatalogue(internal.Offline)
|
||||
if err != nil {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -13,12 +14,13 @@ import (
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/server"
|
||||
sshPkg "coopcloud.tech/abra/pkg/ssh"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var local bool
|
||||
var localFlag = &cli.BoolFlag{
|
||||
Name: "local, l",
|
||||
Name: "local",
|
||||
Aliases: []string{"l"},
|
||||
Usage: "Use local server",
|
||||
Destination: &local,
|
||||
}
|
||||
@ -92,15 +94,16 @@ func createServerDir(name string) (bool, error) {
|
||||
}
|
||||
|
||||
var serverAddCommand = cli.Command{
|
||||
Name: "add",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Add a new server to your configuration",
|
||||
Description: `
|
||||
Add a new server to your configuration so that it can be managed by Abra.
|
||||
Name: "add",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Add a new server",
|
||||
UsageText: "abra server add [options] <domain>",
|
||||
HideHelpCommand: true,
|
||||
Description: `Add a new server to your configuration so that it can be managed by Abra.
|
||||
|
||||
Abra relies on the standard SSH command-line and ~/.ssh/config for client
|
||||
connection details. You must configure an entry per-host in your ~/.ssh/config
|
||||
for each server. For example:
|
||||
for each server:
|
||||
|
||||
Host example.com example
|
||||
Hostname example.com
|
||||
@ -108,10 +111,6 @@ for each server. For example:
|
||||
Port 12345
|
||||
IdentityFile ~/.ssh/example@somewhere
|
||||
|
||||
You can then add a server like so:
|
||||
|
||||
abra server add example.com
|
||||
|
||||
If "--local" is passed, then Abra assumes that the current local server is
|
||||
intended as the target server. This is useful when you want to have your entire
|
||||
Co-op Cloud config located on the server itself, and not on your local
|
||||
@ -119,28 +118,24 @@ developer machine. The domain is then set to "default".
|
||||
|
||||
You can also pass "--no-domain-checks/-D" flag to use any arbitrary name
|
||||
instead of a real domain. The host will be resolved with the "Hostname" entry
|
||||
of your ~/.ssh/config. Checks for a valid online domain will be skipped:
|
||||
|
||||
abra server add -D example`,
|
||||
of your ~/.ssh/config. Checks for a valid online domain will be skipped.`,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.NoDomainChecksFlag,
|
||||
localFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
ArgsUsage: "<name>",
|
||||
Action: func(c *cli.Context) error {
|
||||
if len(c.Args()) > 0 && local || !internal.ValidateSubCmdFlags(c) {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
if cmd.Args().Len() > 0 && local || !internal.ValidateSubCmdFlags(cmd) {
|
||||
err := errors.New("cannot use <name> and --local together")
|
||||
internal.ShowSubcommandHelpAndError(c, err)
|
||||
internal.ShowSubcommandHelpAndError(cmd, err)
|
||||
}
|
||||
|
||||
var name string
|
||||
if local {
|
||||
name = "default"
|
||||
} else {
|
||||
name = internal.ValidateDomain(c)
|
||||
name = internal.ValidateDomain(cmd)
|
||||
}
|
||||
|
||||
// NOTE(d1): reasonable 5 second timeout for connections which can't
|
||||
|
@ -1,29 +1,31 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/context"
|
||||
contextPkg "coopcloud.tech/abra/pkg/context"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/docker/cli/cli/connhelper/ssh"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var serverListCommand = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List managed servers",
|
||||
Name: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Usage: "List managed servers",
|
||||
UsageText: "abra server list [options]",
|
||||
HideHelpCommand: true,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.MachineReadableFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Action: func(c *cli.Context) error {
|
||||
dockerContextStore := context.NewDefaultDockerContextStore()
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
dockerContextStore := contextPkg.NewDefaultDockerContextStore()
|
||||
contexts, err := dockerContextStore.Store.List()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@ -39,14 +41,14 @@ var serverListCommand = cli.Command{
|
||||
|
||||
for _, serverName := range serverNames {
|
||||
var row []string
|
||||
for _, ctx := range contexts {
|
||||
endpoint, err := context.GetContextEndpoint(ctx)
|
||||
for _, dockerCtx := range contexts {
|
||||
endpoint, err := contextPkg.GetContextEndpoint(dockerCtx)
|
||||
if err != nil && strings.Contains(err.Error(), "does not exist") {
|
||||
// No local context found, we can continue safely
|
||||
continue
|
||||
}
|
||||
|
||||
if ctx.Name == serverName {
|
||||
if dockerCtx.Name == serverName {
|
||||
sp, err := ssh.ParseURL(endpoint)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -9,13 +9,14 @@ import (
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var allFilter bool
|
||||
|
||||
var allFilterFlag = &cli.BoolFlag{
|
||||
Name: "all, a",
|
||||
Name: "all",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Remove all unused images not just dangling ones",
|
||||
Destination: &allFilter,
|
||||
}
|
||||
@ -23,17 +24,19 @@ var allFilterFlag = &cli.BoolFlag{
|
||||
var volumesFilter bool
|
||||
|
||||
var volumesFilterFlag = &cli.BoolFlag{
|
||||
Name: "volumes, v",
|
||||
Name: "volumes",
|
||||
Aliases: []string{"v"},
|
||||
Usage: "Prune volumes. This will remove app data, Be Careful!",
|
||||
Destination: &volumesFilter,
|
||||
}
|
||||
|
||||
var serverPruneCommand = cli.Command{
|
||||
Name: "prune",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Prune resources on a server",
|
||||
Description: `
|
||||
Prunes unused containers, networks, and dangling images.
|
||||
Name: "prune",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Prune resources on a server",
|
||||
UsageText: "abra server prune [options] <server>",
|
||||
HideHelpCommand: true,
|
||||
Description: `Prunes unused containers, networks, and dangling images.
|
||||
|
||||
Use "-v/--volumes" to remove volumes that are not associated with a deployed
|
||||
app. This can result in unwanted data loss if not used carefully.`,
|
||||
@ -41,14 +44,12 @@ app. This can result in unwanted data loss if not used carefully.`,
|
||||
Flags: []cli.Flag{
|
||||
allFilterFlag,
|
||||
volumesFilterFlag,
|
||||
internal.DebugFlag,
|
||||
internal.OfflineFlag,
|
||||
internal.NoInputFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.ServerNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
serverName := internal.ValidateServer(c)
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.ServerNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
serverName := internal.ValidateServer(cmd)
|
||||
|
||||
cl, err := client.New(serverName)
|
||||
if err != nil {
|
||||
@ -57,7 +58,6 @@ app. This can result in unwanted data loss if not used carefully.`,
|
||||
|
||||
var args filters.Args
|
||||
|
||||
ctx := context.Background()
|
||||
cr, err := cl.ContainersPrune(ctx, args)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@ -9,29 +10,25 @@ import (
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var serverRemoveCommand = cli.Command{
|
||||
Name: "remove",
|
||||
Aliases: []string{"rm"},
|
||||
ArgsUsage: "<server>",
|
||||
Usage: "Remove a managed server",
|
||||
Description: `
|
||||
Remove a managed server.
|
||||
Name: "remove",
|
||||
Aliases: []string{"rm"},
|
||||
UsageText: "abra server remove [options] <domain>",
|
||||
Usage: "Remove a managed server",
|
||||
HideHelpCommand: true,
|
||||
Description: `Remove a managed server.
|
||||
|
||||
Abra will remove the internal bookkeeping (~/.abra/servers/...) and underlying
|
||||
client connection context. This server will then be lost in time, like tears in
|
||||
rain.`,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.NoInputFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
BashComplete: autocomplete.ServerNameComplete,
|
||||
Action: func(c *cli.Context) error {
|
||||
serverName := internal.ValidateServer(c)
|
||||
Abra will remove the internal bookkeeping ($ABRA_DIR/servers/...) and
|
||||
underlying client connection context. This server will then be lost in time,
|
||||
like tears in rain.`,
|
||||
Before: internal.SubCommandBefore,
|
||||
EnableShellCompletion: true,
|
||||
ShellComplete: autocomplete.ServerNameComplete,
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
serverName := internal.ValidateServer(cmd)
|
||||
|
||||
if err := client.DeleteContext(serverName); err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -1,18 +1,20 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// ServerCommand defines the `abra server` command and its subcommands
|
||||
var ServerCommand = cli.Command{
|
||||
Name: "server",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "Manage servers",
|
||||
Subcommands: []cli.Command{
|
||||
serverAddCommand,
|
||||
serverListCommand,
|
||||
serverRemoveCommand,
|
||||
serverPruneCommand,
|
||||
Name: "server",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "Manage servers",
|
||||
UsageText: "abra server [command] [options] [arguments]",
|
||||
HideHelpCommand: true,
|
||||
Commands: []*cli.Command{
|
||||
&serverAddCommand,
|
||||
&serverListCommand,
|
||||
&serverRemoveCommand,
|
||||
&serverPruneCommand,
|
||||
},
|
||||
}
|
||||
|
@ -23,44 +23,44 @@ import (
|
||||
dockerclient "github.com/docker/docker/client"
|
||||
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
const SERVER = "localhost"
|
||||
|
||||
var majorUpdate bool
|
||||
var majorFlag = &cli.BoolFlag{
|
||||
Name: "major, m",
|
||||
Name: "major",
|
||||
Aliases: []string{"m"},
|
||||
Usage: "Also check for major updates",
|
||||
Destination: &majorUpdate,
|
||||
}
|
||||
|
||||
var updateAll bool
|
||||
var allFlag = &cli.BoolFlag{
|
||||
Name: "all, a",
|
||||
Name: "all",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Update all deployed apps",
|
||||
Destination: &updateAll,
|
||||
}
|
||||
|
||||
// Notify checks for available upgrades
|
||||
var Notify = cli.Command{
|
||||
Name: "notify",
|
||||
Aliases: []string{"n"},
|
||||
Usage: "Check for available upgrades",
|
||||
Name: "notify",
|
||||
Aliases: []string{"n"},
|
||||
Usage: "Check for available upgrades",
|
||||
UsageText: "kadabra notify [options]",
|
||||
HideHelpCommand: true,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
majorFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
Read the deployed app versions and look for new versions in the recipe
|
||||
catalogue.
|
||||
Description: `Notify on new versions for deployed apps.
|
||||
|
||||
If a new patch/minor version is available, a notification is printed.
|
||||
|
||||
Use "--major" to include new major versions.`,
|
||||
Action: func(c *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
cl, err := client.New("default")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@ -92,20 +92,18 @@ Use "--major" to include new major versions.`,
|
||||
|
||||
// UpgradeApp upgrades apps.
|
||||
var UpgradeApp = cli.Command{
|
||||
Name: "upgrade",
|
||||
Aliases: []string{"u"},
|
||||
Usage: "Upgrade apps",
|
||||
ArgsUsage: "<stack-name> <recipe>",
|
||||
Name: "upgrade",
|
||||
Aliases: []string{"u"},
|
||||
Usage: "Upgrade apps",
|
||||
UsageText: "kadabra notify [options] <stack> <recipe>",
|
||||
HideHelpCommand: true,
|
||||
Flags: []cli.Flag{
|
||||
internal.DebugFlag,
|
||||
internal.ChaosFlag,
|
||||
majorFlag,
|
||||
allFlag,
|
||||
internal.OfflineFlag,
|
||||
},
|
||||
Before: internal.SubCommandBefore,
|
||||
Description: `
|
||||
Upgrade an app by specifying stack name and recipe.
|
||||
Description: `Upgrade an app by specifying stack name and recipe.
|
||||
|
||||
Use "--all" to upgrade every deployed app.
|
||||
|
||||
@ -116,15 +114,15 @@ available, the app is upgraded.
|
||||
To include major versions use the "--major" flag. You probably don't want that
|
||||
as it will break things. Only apps that are not deployed with "--chaos" are
|
||||
upgraded, to update chaos deployments use the "--chaos" flag. Use it with care.`,
|
||||
Action: func(c *cli.Context) error {
|
||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||
cl, err := client.New("default")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if !updateAll {
|
||||
stackName := c.Args().Get(0)
|
||||
recipeName := c.Args().Get(1)
|
||||
stackName := cmd.Args().Get(0)
|
||||
recipeName := cmd.Args().Get(1)
|
||||
err = tryUpgrade(cl, stackName, recipeName)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@ -468,25 +466,24 @@ func upgrade(cl *dockerclient.Client, stackName, recipeName, upgradeVersion stri
|
||||
return err
|
||||
}
|
||||
|
||||
func newAbraApp(version, commit string) *cli.App {
|
||||
app := &cli.App{
|
||||
Name: "kadabra",
|
||||
Usage: `The Co-op Cloud auto-updater
|
||||
____ ____ _ _
|
||||
/ ___|___ ___ _ __ / ___| | ___ _ _ __| |
|
||||
| | / _ \ _____ / _ \| '_ \ | | | |/ _ \| | | |/ _' |
|
||||
| |__| (_) |_____| (_) | |_) | | |___| | (_) | |_| | (_| |
|
||||
\____\___/ \___/| .__/ \____|_|\___/ \__,_|\__,_|
|
||||
|_|
|
||||
`,
|
||||
Version: fmt.Sprintf("%s-%s", version, commit[:7]),
|
||||
Commands: []cli.Command{
|
||||
Notify,
|
||||
UpgradeApp,
|
||||
func newAbraApp(version, commit string) *cli.Command {
|
||||
app := &cli.Command{
|
||||
Name: "kadabra",
|
||||
Usage: "The Co-op Cloud auto-updater 🤖🚀",
|
||||
Version: fmt.Sprintf("%s-%s", version, commit[:7]),
|
||||
UsageText: "kadabra [command] [options] [arguments]",
|
||||
HideHelpCommand: true,
|
||||
Flags: []cli.Flag{
|
||||
internal.OfflineFlag,
|
||||
internal.DebugFlag,
|
||||
},
|
||||
Commands: []*cli.Command{
|
||||
&Notify,
|
||||
&UpgradeApp,
|
||||
},
|
||||
}
|
||||
|
||||
app.Before = func(c *cli.Context) error {
|
||||
app.Before = func(ctx context.Context, cmd *cli.Command) error {
|
||||
charmLog.SetDefault(log.Logger)
|
||||
log.Debugf("kadabra version %s, commit %s", version, commit)
|
||||
return nil
|
||||
@ -499,7 +496,7 @@ func newAbraApp(version, commit string) *cli.App {
|
||||
func RunApp(version, commit string) {
|
||||
app := newAbraApp(version, commit)
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
if err := app.Run(context.Background(), os.Args); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
6
go.mod
6
go.mod
@ -2,6 +2,8 @@ module coopcloud.tech/abra
|
||||
|
||||
go 1.21
|
||||
|
||||
replace github.com/urfave/cli/v3 => github.com/fiatjaf/cli/v3 v3.0.0-20240704165307-ad0e1925dd42
|
||||
|
||||
require (
|
||||
coopcloud.tech/tagcmp v0.0.0-20230809071031-eb3e7758d4eb
|
||||
git.coopcloud.tech/coop-cloud/godotenv v1.5.2-0.20231130100509-01bff8284355
|
||||
@ -18,6 +20,7 @@ require (
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/schollz/progressbar/v3 v3.14.4
|
||||
github.com/urfave/cli/v3 v3.0.0-alpha9
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gotest.tools/v3 v3.5.1
|
||||
)
|
||||
@ -36,7 +39,6 @@ require (
|
||||
github.com/charmbracelet/x/ansi v0.1.2 // indirect
|
||||
github.com/cloudflare/circl v1.3.9 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.5 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
@ -84,7 +86,6 @@ require (
|
||||
github.com/prometheus/common v0.55.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/skeema/knownhosts v1.2.2 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
@ -134,7 +135,6 @@ require (
|
||||
github.com/spf13/cobra v1.8.1 // indirect
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||
github.com/urfave/cli v1.22.15
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
golang.org/x/sys v0.22.0
|
||||
)
|
||||
|
13
go.sum
13
go.sum
@ -49,7 +49,6 @@ github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
|
||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
@ -274,7 +273,6 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
@ -357,6 +355,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fiatjaf/cli/v3 v3.0.0-20240704165307-ad0e1925dd42 h1:yId1d3b2PHJ9vnYCxojs9NslXYVQ1iv7svK/CuDRoU0=
|
||||
github.com/fiatjaf/cli/v3 v3.0.0-20240704165307-ad0e1925dd42/go.mod h1:Z1ItyMma7t6I7zHG9OpbExhHQOSkFf/96n+mAZ9MtVI=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
@ -803,7 +803,6 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
@ -861,9 +860,6 @@ github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
@ -871,9 +867,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
@ -893,8 +886,6 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.15 h1:nuqt+pdC/KqswQKhETJjo7pvn/k4xMUxgW6liI7XpnM=
|
||||
github.com/urfave/cli v1.22.15/go.mod h1:wSan1hmo5zeyLGBjRJbzRTNk8gwoYa2B9n4q9dmRIc0=
|
||||
github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI=
|
||||
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||
|
@ -1,22 +1,23 @@
|
||||
package autocomplete
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"coopcloud.tech/abra/pkg/app"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// AppNameComplete copletes app names.
|
||||
func AppNameComplete(c *cli.Context) {
|
||||
func AppNameComplete(ctx context.Context, cmd *cli.Command) {
|
||||
appNames, err := app.GetAppNames()
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
|
||||
if c.NArg() > 0 {
|
||||
if cmd.NArg() > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@ -36,13 +37,13 @@ func ServiceNameComplete(appName string) {
|
||||
}
|
||||
|
||||
// RecipeNameComplete completes recipe names.
|
||||
func RecipeNameComplete(c *cli.Context) {
|
||||
func RecipeNameComplete(ctx context.Context, cmd *cli.Command) {
|
||||
catl, err := recipe.ReadRecipeCatalogue(false)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
|
||||
if c.NArg() > 0 {
|
||||
if cmd.NArg() > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@ -66,13 +67,13 @@ func RecipeVersionComplete(recipeName string) {
|
||||
}
|
||||
|
||||
// ServerNameComplete completes server names.
|
||||
func ServerNameComplete(c *cli.Context) {
|
||||
func ServerNameComplete(ctx context.Context, cmd *cli.Command) {
|
||||
files, err := app.LoadAppFiles("")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if c.NArg() > 0 {
|
||||
if cmd.NArg() > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@ -82,8 +83,8 @@ func ServerNameComplete(c *cli.Context) {
|
||||
}
|
||||
|
||||
// SubcommandComplete completes sub-commands.
|
||||
func SubcommandComplete(c *cli.Context) {
|
||||
if c.NArg() > 0 {
|
||||
func SubcommandComplete(ctx context.Context, cmd *cli.Command) {
|
||||
if cmd.NArg() > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -8,9 +8,9 @@ _cli_bash_autocomplete() {
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
if [[ "$cur" == "-"* ]]; then
|
||||
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-bash-completion )
|
||||
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-shell-completion )
|
||||
else
|
||||
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
|
||||
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-shell-completion )
|
||||
fi
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
|
@ -1,5 +1,5 @@
|
||||
function complete_abra_args
|
||||
set -l cmd (commandline -poc) --generate-bash-completion
|
||||
set -l cmd (commandline -poc) --generate-shell-completion
|
||||
$cmd
|
||||
end
|
||||
complete -c abra -f -n "not __fish_seen_subcommand_from -h --help -v --version complete_abra_args" -a "(complete_abra_args)"
|
||||
|
@ -2,7 +2,7 @@ $fn = $($MyInvocation.MyCommand.Name)
|
||||
$name = $fn -replace "(.*)\.ps1$", '$1'
|
||||
Register-ArgumentCompleter -Native -CommandName $name -ScriptBlock {
|
||||
param($commandName, $wordToComplete, $cursorPosition)
|
||||
$other = "$wordToComplete --generate-bash-completion"
|
||||
$other = "$wordToComplete --generate-shell-completion"
|
||||
Invoke-Expression $other | ForEach-Object {
|
||||
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
|
||||
}
|
||||
|
@ -6,9 +6,9 @@ _cli_zsh_autocomplete() {
|
||||
local cur
|
||||
cur=${words[-1]}
|
||||
if [[ "$cur" == "-"* ]]; then
|
||||
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}")
|
||||
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-shell-completion)}")
|
||||
else
|
||||
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}")
|
||||
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-shell-completion)}")
|
||||
fi
|
||||
|
||||
if [[ "${opts[1]}" != "" ]]; then
|
||||
|
Loading…
x
Reference in New Issue
Block a user