Documentation ¶
Index ¶
- Variables
- func AppEnvAction(c *cli.Context, providers app.Providers, fn AppEnvActionFn) error
- func CancellableAction(fn func(ctx context.Context) error) error
- func DetectAppVersion(c *cli.Context) string
- func GetOrg(c *cli.Context, profile config.Profile) string
- func GetProfile(c *cli.Context) string
- func ProfileAction(c *cli.Context, fn ProfileFn) error
- func SetupProfileCmd(c *cli.Context) (*config.Profile, api.Config, error)
- func WatchAction(ctx context.Context, watchInterval time.Duration, fn func(w io.Writer) error) error
- type AppEnvActionFn
- type AppWorkspaceInfo
- type ErrMultipleAppsFound
- type ModuleSource
- type NsFinder
- func (f NsFinder) FindAppAndStack(appName, stackName string) (*types.Application, *types.Stack, error)
- func (f NsFinder) FindAppDetails(appName, stackName, envName string) (app.Details, error)
- func (f NsFinder) FindStack(stackName string) (*types.Stack, error)
- func (f NsFinder) GetAppModule(client api.Client, app types.Application) (*types.Module, error)
- func (f NsFinder) GetEnv(stackId int64, envName string) (*types.Environment, error)
- type NsStatus
- type ProfileFn
- type TableBuffer
Constants ¶
This section is empty.
Variables ¶
var ( AddressFlag = &cli.StringFlag{ Name: "address", Value: api.DefaultAddress, Usage: "Nullstone API Address", } ApiKeyFlag = &cli.StringFlag{ Name: "api-key", Value: "", Usage: "Nullstone API Key", } )
var AppSourceFlag = &cli.StringFlag{ Name: "source", Usage: `The source artifact to push. app/container: This is the docker image to push. This follows the same syntax as 'docker push NAME[:TAG]'. app/serverless: This is a .zip archive to push.`, Required: true, }
var AppVersionFlag = &cli.StringFlag{
Name: "version",
Usage: `Push/Deploy the artifact with this version.
If not specified, will retrieve short sha from your latest commit.
app/container: If specified, will push the docker image with version as the image tag. Otherwise, uses source tag.
app/serverless: This is required to upload the artifact.`,
}
var Apps = &cli.Command{ Name: "apps", Usage: "View and modify applications", UsageText: "nullstone apps [subcommand]", Subcommands: []*cli.Command{ AppsList, }, }
var AppsList = &cli.Command{ Name: "list", Usage: "List applications", UsageText: "nullstone apps list", Flags: []cli.Flag{ &cli.BoolFlag{ Name: "detail", Aliases: []string{"d"}, }, }, Action: func(c *cli.Context) error { return ProfileAction(c, func(cfg api.Config) error { client := api.Client{Config: cfg} allApps, err := client.Apps().List() if err != nil { return fmt.Errorf("error listing applications: %w", err) } finder := NsFinder{Config: cfg} if c.IsSet("detail") { appDetails := make([]string, len(allApps)+1) appDetails[0] = "ID|Name|Reference|Category|Type|Module|Stack|Framework" for i, app := range allApps { var appCategory types.CategoryName var appType string if appModule, err := finder.GetAppModule(client, app); err == nil { appCategory = appModule.Category appType = appModule.Type } appDetails[i+1] = fmt.Sprintf("%d|%s|%s|%s|%s|%s|%s|%s", app.Id, app.Name, app.Reference, appCategory, appType, app.ModuleSource, app.StackName, app.Framework) } fmt.Println(columnize.Format(appDetails, columnize.DefaultConfig())) } else { for _, app := range allApps { fmt.Println(app.Name) } } return nil }) }, }
var Configure = &cli.Command{ Name: "configure", Flags: []cli.Flag{ AddressFlag, ApiKeyFlag, }, Action: func(c *cli.Context) error { apiKey := c.String(ApiKeyFlag.Name) if apiKey == "" { fmt.Print("Enter API Key: ") rawApiKey, err := terminal.ReadPassword(int(syscall.Stdin)) if err != nil { return fmt.Errorf("error reading password: %w", err) } fmt.Println() apiKey = string(rawApiKey) } profile := config.Profile{ Name: GetProfile(c), Address: c.String(AddressFlag.Name), ApiKey: apiKey, } if err := profile.Save(); err != nil { return fmt.Errorf("error configuring profile: %w", err) } fmt.Fprintln(os.Stderr, "nullstone configured successfully!") return nil }, }
var Deploy = func(providers app.Providers) *cli.Command { return &cli.Command{ Name: "deploy", Usage: "Deploy application", UsageText: "nullstone deploy [options] <app-name> <env-name>", Flags: []cli.Flag{ StackFlag, AppVersionFlag, }, Action: func(c *cli.Context) error { return AppEnvAction(c, providers, func(ctx context.Context, cfg api.Config, provider app.Provider, details app.Details) error { userConfig := map[string]string{ "version": DetectAppVersion(c), } return provider.Deploy(cfg, details, userConfig) }) }, } }
var Envs = &cli.Command{ Name: "envs", Usage: "View and modify environments", UsageText: "nullstone envs [subcommand]", Subcommands: []*cli.Command{ EnvsList, }, }
var EnvsList = &cli.Command{ Name: "list", Usage: "List environments", UsageText: "nullstone envs list <stack-name>", Flags: []cli.Flag{ &cli.BoolFlag{ Name: "detail", Aliases: []string{"d"}, }, }, Action: func(c *cli.Context) error { return ProfileAction(c, func(cfg api.Config) error { if c.NArg() != 1 { cli.ShowCommandHelp(c, c.Command.Name) return fmt.Errorf("stack-name is required to list environments") } stackName := c.Args().Get(0) finder := NsFinder{Config: cfg} stack, err := finder.FindStack(stackName) if err != nil { return fmt.Errorf("error retrieving stack: %w", err) } else if stack == nil { return fmt.Errorf("stack %s does not exist", stackName) } client := api.Client{Config: cfg} envs, err := client.Environments().List(stack.Id) if err != nil { return fmt.Errorf("error listing environments: %w", err) } sort.SliceStable(envs, func(i, j int) bool { return envs[i].PipelineOrder < envs[i].PipelineOrder }) if c.IsSet("detail") { envDetails := make([]string, len(envs)+1) envDetails[0] = "ID|Name" for i, env := range envs { envDetails[i+1] = fmt.Sprintf("%d|%s", env.Id, env.Name) } fmt.Println(columnize.Format(envDetails, columnize.DefaultConfig())) } else { for _, env := range envs { fmt.Println(env.Name) } } return nil }) }, }
var ErrInvalidModuleSource = errors.New("invalid module source")
var (
ErrMissingOrg = errors.New("An organization has not been configured with this profile. See 'nullstone set-org -h' for more details.")
)
var Launch = func(providers app.Providers, logProviders app_logs.Providers) *cli.Command { return &cli.Command{ Name: "launch", Usage: "Launch application (push, deploy, log)", UsageText: "nullstone launch [options] <app-name> <env-name>", Flags: []cli.Flag{ StackFlag, AppSourceFlag, AppVersionFlag, }, Action: func(c *cli.Context) error { return AppEnvAction(c, providers, func(ctx context.Context, cfg api.Config, provider app.Provider, details app.Details) error { logger := log.New(os.Stderr, "", 0) userConfig := map[string]string{ "source": c.String("source"), "version": DetectAppVersion(c), } logger.Println("Pushing app artifact...") if err := provider.Push(cfg, details, userConfig); err != nil { return fmt.Errorf("error pushing artifact: %w", err) } logger.Println() logger.Println("Deploying application...") if err := provider.Deploy(cfg, details, userConfig); err != nil { return fmt.Errorf("error deploying app: %w", err) } logger.Println() logger.Println("Tailing application logs...") logProvider, err := logProviders.Identify(provider.DefaultLogProvider(), cfg, details) if err != nil { return err } return logProvider.Stream(ctx, cfg, details, config.LogStreamOptions{Out: os.Stdout}) }) }, } }
Launch command performs push, deploy, and logs
var Logs = func(providers app.Providers, logProviders app_logs.Providers) *cli.Command { return &cli.Command{ Name: "logs", Usage: "Emit application logs", UsageText: "nullstone logs [options] <app-name> <env-name>", Flags: []cli.Flag{ StackFlag, &cli.DurationFlag{ Name: "start-time", Aliases: []string{"s"}, DefaultText: "1h", Usage: ` Emit log events that occur after the specified start-time. This is a golang duration relative to the time the command is issued. Examples: '5s' (5 seconds ago), '1m' (1 minute ago), '24h' (24 hours ago) `, }, &cli.DurationFlag{ Name: "end-time", Aliases: []string{"e"}, Usage: ` Emit log events that occur before the specified end-time. This is a golang duration relative to the time the command is issued. Examples: '5s' (5 seconds ago), '1m' (1 minute ago), '24h' (24 hours ago) `, }, &cli.DurationFlag{ Name: "interval", DefaultText: "1s", Usage: `Set --interval to a golang duration to control how often to pull new log events. This will do nothing unless --tail is set. `, }, &cli.BoolFlag{ Name: "tail", Aliases: []string{"t"}, Usage: `Set tail to watch log events and emit as they are reported. Use --interval to control how often to query log events. This is off by default, command will exit as soon as current log events are emitted.`, }, }, Action: func(c *cli.Context) error { return AppEnvAction(c, providers, func(ctx context.Context, cfg api.Config, provider app.Provider, details app.Details) error { logStreamOptions := config.LogStreamOptions{ WatchInterval: -1 * time.Second, Out: os.Stdout, } if c.IsSet("start-time") { absoluteTime := time.Now().Add(-c.Duration("start-time")) logStreamOptions.StartTime = &absoluteTime } if c.IsSet("end-time") { absoluteTime := time.Now().Add(-c.Duration("end-time")) logStreamOptions.EndTime = &absoluteTime } if c.IsSet("tail") { logStreamOptions.WatchInterval = time.Duration(0) if c.IsSet("interval") { logStreamOptions.WatchInterval = c.Duration("interval") } } logProvider, err := logProviders.Identify(provider.DefaultLogProvider(), cfg, details) if err != nil { return err } return logProvider.Stream(ctx, cfg, details, logStreamOptions) }) }, } }
var OrgFlag = &cli.StringFlag{ Name: "org", EnvVars: []string{"NULLSTONE_ORG"}, Usage: `Nullstone organization name used to contextualize API calls. If this flag is not specified, the nullstone CLI will use ~/.nullstone/<profile>/org file.`, }
OrgFlag defines a flag that the CLI uses
to contextualize API calls by that organization within Nullstone
The organization takes the following precedence:
`--org` flag `NULLSTONE_ORG` env var `~/.nullstone/<profile>/org` file
var ProfileFlag = &cli.StringFlag{ Name: "profile", EnvVars: []string{"NULLSTONE_PROFILE"}, Value: "default", Usage: "Name of profile", }
var Push = func(providers app.Providers) *cli.Command { return &cli.Command{ Name: "push", Usage: "Push artifact", UsageText: "nullstone push [options] <app-name> <env-name>", Flags: []cli.Flag{ StackFlag, AppSourceFlag, AppVersionFlag, }, Action: func(c *cli.Context) error { return AppEnvAction(c, providers, func(ctx context.Context, cfg api.Config, provider app.Provider, details app.Details) error { userConfig := map[string]string{ "source": c.String("source"), "version": DetectAppVersion(c), } return provider.Push(cfg, details, userConfig) }) }, } }
Push command performs a docker push to an authenticated image registry configured against an app/container
var SetOrg = &cli.Command{ Name: "set-org", Usage: "Set the organization for the CLI", UsageText: `Most Nullstone CLI commands require a configured nullstone organization to operate. This command will set the organization for the current profile. If you wish to set the organization per command, use the global --org flag instead.`, Flags: []cli.Flag{}, Action: func(c *cli.Context) error { profile, err := config.LoadProfile(GetProfile(c)) if err != nil { return err } if c.NArg() != 1 { return cli.ShowCommandHelp(c, "set-org") } orgName := c.Args().Get(0) if err := profile.SaveOrg(orgName); err != nil { return err } fmt.Fprintf(os.Stderr, "Organization set to %s for %s profile\n", orgName, profile.Name) return nil }, }
var StackFlag = &cli.StringFlag{
Name: "stack",
Usage: `The stack name where the app resides.
This is only required if multiple apps have the same 'app-name'.`,
}
var Stacks = &cli.Command{ Name: "stacks", Usage: "View and modify stacks", UsageText: "nullstone stacks [subcommand]", Subcommands: []*cli.Command{ StacksList, }, }
var StacksList = &cli.Command{ Name: "list", Usage: "List stacks", UsageText: "nullstone stacks list", Flags: []cli.Flag{ &cli.BoolFlag{ Name: "detail", Aliases: []string{"d"}, }, }, Action: func(c *cli.Context) error { return ProfileAction(c, func(cfg api.Config) error { client := api.Client{Config: cfg} allStacks, err := client.Stacks().List() if err != nil { return fmt.Errorf("error listing stacks: %w", err) } if c.IsSet("detail") { stackDetails := make([]string, len(allStacks)+1) stackDetails[0] = "ID|Name|Description" for i, stack := range allStacks { stackDetails[i+1] = fmt.Sprintf("%d|%s|%s", stack.Id, stack.Name, stack.Description) } fmt.Println(columnize.Format(stackDetails, columnize.DefaultConfig())) } else { for _, stack := range allStacks { fmt.Println(stack.Name) } } return nil }) }, }
var Status = func(providers app.Providers) *cli.Command { return &cli.Command{ Name: "status", Usage: "Application Status", UsageText: "nullstone status [options] <app-name> [<env-name>]", Flags: []cli.Flag{ StackFlag, AppVersionFlag, &cli.BoolFlag{ Name: "watch", Aliases: []string{"w"}, }, }, Action: func(c *cli.Context) error { return ProfileAction(c, func(cfg api.Config) error { return CancellableAction(func(ctx context.Context) error { var appName, envName string stackName := c.String("stack-name") watchInterval := -1 * time.Second if c.IsSet("watch") { watchInterval = defaultWatchInterval } switch c.NArg() { case 1: appName = c.Args().Get(0) return appStatus(ctx, cfg, providers, watchInterval, stackName, appName) case 2: appName = c.Args().Get(0) envName = c.Args().Get(1) return appEnvStatus(ctx, cfg, providers, watchInterval, stackName, appName, envName) default: cli.ShowCommandHelp(c, c.Command.Name) return fmt.Errorf("invalid usage") } }) }) }, } }
Functions ¶
func AppEnvAction ¶ added in v0.0.26
func AppEnvAction(c *cli.Context, providers app.Providers, fn AppEnvActionFn) error
func CancellableAction ¶ added in v0.0.26
func DetectAppVersion ¶ added in v0.0.28
func DetectAppVersion(c *cli.Context) string
func GetProfile ¶ added in v0.0.4
func GetProfile(c *cli.Context) string
func ProfileAction ¶ added in v0.0.26
func SetupProfileCmd ¶ added in v0.0.7
Types ¶
type AppEnvActionFn ¶ added in v0.0.26
type AppWorkspaceInfo ¶ added in v0.0.26
type ErrMultipleAppsFound ¶ added in v0.0.11
func (ErrMultipleAppsFound) Error ¶ added in v0.0.11
func (e ErrMultipleAppsFound) Error() string
type ModuleSource ¶ added in v0.0.23
func ParseSource ¶ added in v0.0.23
func ParseSource(source string) (*ModuleSource, error)
type NsFinder ¶ added in v0.0.11
type NsFinder struct {
Config api.Config
}
NsFinder is an object that provides a consistent querying approach for nullstone objects through the CLI It provides nice error messages that are tailored for the user flow of CLI commands
func (NsFinder) FindAppAndStack ¶ added in v0.0.26
func (NsFinder) FindAppDetails ¶ added in v0.0.26
FindAppDetails retrieves the app, env, and workspace stackName is optional -- If multiple apps are found, this will return an error
func (NsFinder) GetAppModule ¶ added in v0.0.23
type NsStatus ¶ added in v0.0.26
type NsStatus struct {
Config api.Config
}
func (NsStatus) GetAppWorkspaceInfo ¶ added in v0.0.26
func (s NsStatus) GetAppWorkspaceInfo(application *types.Application, env *types.Environment) (AppWorkspaceInfo, error)
type TableBuffer ¶ added in v0.0.26
TableBuffer builds a table of data to display on the terminal The TableBuffer guarantees safe merging of rows with potentially different field names Example: If a user is migrating an app from container to serverless,
it's possible that the infrastructure has not fully propagated
func (*TableBuffer) AddFields ¶ added in v0.0.26
func (b *TableBuffer) AddFields(fields ...string)
func (*TableBuffer) AddRow ¶ added in v0.0.26
func (b *TableBuffer) AddRow(data map[string]interface{})
func (*TableBuffer) String ¶ added in v0.0.26
func (b *TableBuffer) String() string
func (*TableBuffer) Values ¶ added in v0.0.26
func (b *TableBuffer) Values() [][]string
Source Files ¶
- app_env_action.go
- apps.go
- cancellable_action.go
- configure.go
- deploy.go
- envs.go
- flag_app_source.go
- flag_app_version.go
- flag_org.go
- flag_profile.go
- flag_stack.go
- get_commit_sha.go
- launch.go
- logs.go
- ns_finder.go
- ns_status.go
- profile_action.go
- push.go
- set_org.go
- setup_profile_cmd.go
- stacks.go
- status.go
- table_buffer.go
- watch_action.go