-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
657 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package deployments | ||
|
||
import "github.com/urfave/cli/v2" | ||
|
||
const flagSubdomain = "subdomain" | ||
|
||
func commonFlags() []cli.Flag { | ||
return []cli.Flag{ | ||
&cli.StringFlag{ //nolint:exhaustruct | ||
Name: flagSubdomain, | ||
Usage: "Project's subdomain to operate on, defaults to linked project", | ||
EnvVars: []string{"NHOST_SUBDOMAIN"}, | ||
}, | ||
} | ||
} | ||
|
||
func Command() *cli.Command { | ||
return &cli.Command{ //nolint:exhaustruct | ||
Name: "deployments", | ||
Aliases: []string{}, | ||
Usage: "Manage deployments", | ||
Subcommands: []*cli.Command{ | ||
CommandList(), | ||
CommandLogs(), | ||
CommandNew(), | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package deployments | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
"github.com/nhost/cli/clienv" | ||
"github.com/nhost/cli/nhostclient/graphql" | ||
"github.com/urfave/cli/v2" | ||
) | ||
|
||
func CommandList() *cli.Command { | ||
return &cli.Command{ //nolint:exhaustruct | ||
Name: "list", | ||
Aliases: []string{}, | ||
Usage: "List deployments in the cloud environment", | ||
Action: commandList, | ||
Flags: commonFlags(), | ||
} | ||
} | ||
|
||
func printDeployments(ce *clienv.CliEnv, deployments []*graphql.ListDeployments_Deployments) { | ||
id := clienv.Column{ | ||
Header: "ID", | ||
Rows: make([]string, 0), | ||
} | ||
|
||
date := clienv.Column{ | ||
Header: "Date", | ||
Rows: make([]string, 0), | ||
} | ||
|
||
duration := clienv.Column{ | ||
Header: "Duration", | ||
Rows: make([]string, 0), | ||
} | ||
|
||
status := clienv.Column{ | ||
Header: "Status", | ||
Rows: make([]string, 0), | ||
} | ||
|
||
user := clienv.Column{ | ||
Header: "User", | ||
Rows: make([]string, 0), | ||
} | ||
|
||
ref := clienv.Column{ | ||
Header: "Ref", | ||
Rows: make([]string, 0), | ||
} | ||
|
||
message := clienv.Column{ | ||
Header: "Message", | ||
Rows: make([]string, 0), | ||
} | ||
|
||
for _, d := range deployments { | ||
var startedAt time.Time | ||
if d.DeploymentStartedAt != nil && !d.DeploymentStartedAt.IsZero() { | ||
startedAt = *d.DeploymentStartedAt | ||
} | ||
|
||
var endedAt time.Time | ||
var deplPuration time.Duration | ||
if d.DeploymentEndedAt != nil && !d.DeploymentEndedAt.IsZero() { | ||
endedAt = *d.DeploymentEndedAt | ||
deplPuration = endedAt.Sub(startedAt) | ||
} | ||
|
||
id.Rows = append(id.Rows, d.ID) | ||
date.Rows = append(date.Rows, startedAt.Format(time.RFC3339)) | ||
duration.Rows = append(duration.Rows, deplPuration.String()) | ||
status.Rows = append(status.Rows, *d.DeploymentStatus) | ||
user.Rows = append(user.Rows, *d.CommitUserName) | ||
ref.Rows = append(ref.Rows, d.CommitSha) | ||
message.Rows = append(message.Rows, *d.CommitMessage) | ||
} | ||
|
||
ce.Println("%s", clienv.Table(id, date, duration, status, user, ref, message)) | ||
} | ||
|
||
func commandList(cCtx *cli.Context) error { | ||
ce := clienv.FromCLI(cCtx) | ||
|
||
proj, err := ce.GetAppInfo(cCtx.Context, cCtx.String(flagSubdomain)) | ||
if err != nil { | ||
return fmt.Errorf("failed to get app info: %w", err) | ||
} | ||
|
||
cl, err := ce.GetNhostClient(cCtx.Context) | ||
if err != nil { | ||
return fmt.Errorf("failed to get nhost client: %w", err) | ||
} | ||
deployments, err := cl.ListDeployments( | ||
cCtx.Context, | ||
proj.ID, | ||
) | ||
if err != nil { | ||
return fmt.Errorf("failed to get deployments: %w", err) | ||
} | ||
|
||
printDeployments(ce, deployments.GetDeployments()) | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
package deployments | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/nhost/cli/clienv" | ||
"github.com/nhost/cli/nhostclient" | ||
"github.com/urfave/cli/v2" | ||
) | ||
|
||
const ( | ||
flagFollow = "follow" | ||
flagTimeout = "timeout" | ||
) | ||
|
||
func CommandLogs() *cli.Command { | ||
return &cli.Command{ //nolint:exhaustruct | ||
Name: "logs", | ||
Aliases: []string{}, | ||
Usage: "View deployments logs in the cloud environment", | ||
Action: commandLogs, | ||
ArgsUsage: "<deployment_id>", | ||
Flags: append( | ||
commonFlags(), | ||
[]cli.Flag{ | ||
&cli.BoolFlag{ //nolint:exhaustruct | ||
Name: flagFollow, | ||
Usage: "Specify if the logs should be streamed", | ||
Value: false, | ||
}, | ||
&cli.DurationFlag{ //nolint:exhaustruct | ||
Name: flagTimeout, | ||
Usage: "Specify the timeout for streaming logs", | ||
Value: time.Minute * 5, //nolint:mnd | ||
}, | ||
}..., | ||
), | ||
} | ||
} | ||
|
||
func showLogsSimple( | ||
ctx context.Context, | ||
ce *clienv.CliEnv, | ||
cl *nhostclient.Client, | ||
deploymentID string, | ||
) error { | ||
resp, err := cl.GetDeploymentLogs(ctx, deploymentID) | ||
if err != nil { | ||
return fmt.Errorf("failed to get deployments: %w", err) | ||
} | ||
|
||
for _, log := range resp.GetDeploymentLogs() { | ||
ce.Println( | ||
"%s %s", | ||
log.GetCreatedAt().Format(time.RFC3339), | ||
log.GetMessage(), | ||
) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func showLogsFollow( | ||
ctx context.Context, | ||
ce *clienv.CliEnv, | ||
cl *nhostclient.Client, | ||
deploymentID string, | ||
) (string, error) { | ||
ticker := time.NewTicker(time.Second * 2) //nolint:mnd | ||
|
||
printed := make(map[string]struct{}) | ||
|
||
for { | ||
select { | ||
case <-ctx.Done(): | ||
return "", nil | ||
case <-ticker.C: | ||
resp, err := cl.GetDeploymentLogs(ctx, deploymentID) | ||
if err != nil { | ||
return "", fmt.Errorf("failed to get deployments: %w", err) | ||
} | ||
|
||
for _, log := range resp.GetDeploymentLogs() { | ||
if _, ok := printed[log.GetID()]; !ok { | ||
ce.Println( | ||
"%s %s", | ||
log.GetCreatedAt().Format(time.RFC3339), | ||
log.GetMessage(), | ||
) | ||
printed[log.GetID()] = struct{}{} | ||
} | ||
} | ||
|
||
if resp.Deployment.DeploymentEndedAt != nil { | ||
return *resp.Deployment.DeploymentStatus, nil | ||
} | ||
} | ||
} | ||
} | ||
|
||
func commandLogs(cCtx *cli.Context) error { | ||
deploymentID := cCtx.Args().First() | ||
if deploymentID == "" { | ||
return errors.New("deployment_id is required") //nolint:goerr113 | ||
} | ||
|
||
ce := clienv.FromCLI(cCtx) | ||
|
||
cl, err := ce.GetNhostClient(cCtx.Context) | ||
if err != nil { | ||
return fmt.Errorf("failed to get nhost client: %w", err) | ||
} | ||
|
||
if cCtx.Bool(flagFollow) { | ||
ctx, cancel := context.WithTimeout(cCtx.Context, cCtx.Duration(flagTimeout)) | ||
defer cancel() | ||
|
||
if _, err := showLogsFollow(ctx, ce, cl, deploymentID); err != nil { | ||
return err | ||
} | ||
} else { | ||
if err := showLogsSimple(cCtx.Context, ce, cl, deploymentID); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package deployments | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/nhost/cli/clienv" | ||
"github.com/nhost/cli/nhostclient/graphql" | ||
"github.com/urfave/cli/v2" | ||
) | ||
|
||
const ( | ||
flagRef = "ref" | ||
flagMessage = "message" | ||
flagUser = "user" | ||
flagUserAvatarURL = "user-avatar-url" | ||
) | ||
|
||
func CommandNew() *cli.Command { | ||
return &cli.Command{ //nolint:exhaustruct | ||
Name: "new", | ||
Aliases: []string{}, | ||
Usage: "[EXPERIMENTAL] Create a new deployment", | ||
ArgsUsage: "<git_ref>", | ||
Action: commandNew, | ||
Flags: append( | ||
commonFlags(), | ||
[]cli.Flag{ | ||
&cli.BoolFlag{ //nolint:exhaustruct | ||
Name: flagFollow, | ||
Usage: "Specify if the logs should be streamed. If set, the command will wait for the deployment to finish and stream the logs. If the deployment fails the command will return an error.", //nolint:lll | ||
Value: false, | ||
}, | ||
&cli.DurationFlag{ //nolint:exhaustruct | ||
Name: flagTimeout, | ||
Usage: "Specify the timeout for streaming logs", | ||
Value: time.Minute * 5, //nolint:mnd | ||
}, | ||
&cli.StringFlag{ //nolint:exhaustruct | ||
Name: flagRef, | ||
Usage: "Git reference", | ||
EnvVars: []string{"GITHUB_SHA"}, | ||
Required: true, | ||
}, | ||
&cli.StringFlag{ //nolint:exhaustruct | ||
Name: flagMessage, | ||
Usage: "Commit message", | ||
Required: true, | ||
}, | ||
&cli.StringFlag{ //nolint:exhaustruct | ||
Name: flagUser, | ||
Usage: "Commit user name", | ||
EnvVars: []string{"GITHUB_ACTOR"}, | ||
Required: true, | ||
}, | ||
&cli.StringFlag{ //nolint:exhaustruct | ||
Name: flagUserAvatarURL, | ||
Usage: "Commit user avatar URL", | ||
}, | ||
}..., | ||
), | ||
} | ||
} | ||
|
||
func ptr[i any](v i) *i { | ||
return &v | ||
} | ||
|
||
func commandNew(cCtx *cli.Context) error { | ||
ce := clienv.FromCLI(cCtx) | ||
|
||
cl, err := ce.GetNhostClient(cCtx.Context) | ||
if err != nil { | ||
return fmt.Errorf("failed to get nhost client: %w", err) | ||
} | ||
|
||
proj, err := ce.GetAppInfo(cCtx.Context, cCtx.String(flagSubdomain)) | ||
if err != nil { | ||
return fmt.Errorf("failed to get app info: %w", err) | ||
} | ||
|
||
resp, err := cl.InsertDeployment( | ||
cCtx.Context, | ||
graphql.DeploymentsInsertInput{ | ||
App: nil, | ||
AppID: ptr(proj.ID), | ||
CommitMessage: ptr(cCtx.String(flagMessage)), | ||
CommitSha: ptr(cCtx.String(flagRef)), | ||
CommitUserAvatarURL: ptr(cCtx.String(flagUserAvatarURL)), | ||
CommitUserName: ptr(cCtx.String(flagUser)), | ||
DeploymentStatus: ptr("SCHEDULED"), | ||
}, | ||
) | ||
if err != nil { | ||
return fmt.Errorf("failed to insert deployment: %w", err) | ||
} | ||
|
||
ce.Println("Deployment created: %s", resp.InsertDeployment.ID) | ||
|
||
if cCtx.Bool(flagFollow) { | ||
ce.Println("") | ||
ctx, cancel := context.WithTimeout(cCtx.Context, cCtx.Duration(flagTimeout)) | ||
defer cancel() | ||
|
||
status, err := showLogsFollow(ctx, ce, cl, resp.InsertDeployment.ID) | ||
if err != nil { | ||
return fmt.Errorf("error streaming logs: %w", err) | ||
} | ||
|
||
if status != "DEPLOYED" { | ||
return fmt.Errorf("deployment failed: %s", status) //nolint:goerr113 | ||
} | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.