Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions cmd/account/access/access.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package access

import (
"fmt"

"github.com/rs/zerolog"
"github.com/spf13/cobra"

"github.com/smartcontractkit/cre-cli/internal/accessrequest"
"github.com/smartcontractkit/cre-cli/internal/credentials"
"github.com/smartcontractkit/cre-cli/internal/runtime"
)

func New(runtimeCtx *runtime.Context) *cobra.Command {
cmd := &cobra.Command{
Use: "access",
Short: "Check or request deployment access",
Long: "Check your deployment access status or request access to deploy workflows.",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
h := NewHandler(runtimeCtx, cmd.InOrStdin())
return h.Execute()
},
}

return cmd
}

type Handler struct {
log *zerolog.Logger
credentials *credentials.Credentials
requester *accessrequest.Requester
}

func NewHandler(ctx *runtime.Context, stdin interface{ Read([]byte) (int, error) }) *Handler {
return &Handler{
log: ctx.Logger,
credentials: ctx.Credentials,
requester: accessrequest.NewRequester(ctx.Credentials, ctx.Logger, stdin),
}
}

func (h *Handler) Execute() error {
deployAccess, err := h.credentials.GetDeploymentAccessStatus()
if err != nil {
return fmt.Errorf("failed to check deployment access: %w", err)
}

if deployAccess.HasAccess {
fmt.Println("")
fmt.Println("You have deployment access enabled for your organization.")
fmt.Println("")
fmt.Println("You're all set to deploy workflows. Get started with:")
fmt.Println("")
fmt.Println(" cre workflow deploy")
fmt.Println("")
fmt.Println("For more information, run 'cre workflow deploy --help'")
fmt.Println("")
return nil
}

return h.requester.PromptAndSubmitRequest()
}
6 changes: 4 additions & 2 deletions cmd/account/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package account
import (
"github.com/spf13/cobra"

"github.com/smartcontractkit/cre-cli/cmd/account/access"
"github.com/smartcontractkit/cre-cli/cmd/account/link_key"
"github.com/smartcontractkit/cre-cli/cmd/account/list_key"
"github.com/smartcontractkit/cre-cli/cmd/account/unlink_key"
Expand All @@ -12,10 +13,11 @@ import (
func New(runtimeContext *runtime.Context) *cobra.Command {
accountCmd := &cobra.Command{
Use: "account",
Short: "Manages account",
Long: "Manage your linked public key addresses for workflow operations.",
Short: "Manage account and request deploy access",
Long: "Manage your linked public key addresses for workflow operations and request deployment access.",
}

accountCmd.AddCommand(access.New(runtimeContext))
accountCmd.AddCommand(link_key.New(runtimeContext))
accountCmd.AddCommand(unlink_key.New(runtimeContext))
accountCmd.AddCommand(list_key.New(runtimeContext))
Expand Down
20 changes: 19 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/smartcontractkit/cre-cli/cmd/workflow"
"github.com/smartcontractkit/cre-cli/internal/constants"
"github.com/smartcontractkit/cre-cli/internal/context"
"github.com/smartcontractkit/cre-cli/internal/credentials"
"github.com/smartcontractkit/cre-cli/internal/logger"
"github.com/smartcontractkit/cre-cli/internal/runtime"
"github.com/smartcontractkit/cre-cli/internal/settings"
Expand Down Expand Up @@ -126,7 +127,7 @@ func newRootCommand() *cobra.Command {

// Check if organization is ungated for commands that require it
cmdPath := cmd.CommandPath()
if cmdPath == "cre account link-key" || cmdPath == "cre workflow deploy" {
if cmdPath == "cre account link-key" {
if err := runtimeContext.Credentials.CheckIsUngatedOrganization(); err != nil {
return err
}
Expand Down Expand Up @@ -174,6 +175,22 @@ func newRootCommand() *cobra.Command {
return false
})

cobra.AddTemplateFunc("needsDeployAccess", func() bool {
creds := runtimeContext.Credentials
if creds == nil {
var err error
creds, err = credentials.New(rootLogger)
if err != nil {
return false
}
}
deployAccess, err := creds.GetDeploymentAccessStatus()
if err != nil {
return false
}
return !deployAccess.HasAccess
})

rootCmd.SetHelpTemplate(helpTemplate)

// Definition of global flags:
Expand Down Expand Up @@ -261,6 +278,7 @@ func isLoadSettings(cmd *cobra.Command) bool {
"cre login": {},
"cre logout": {},
"cre whoami": {},
"cre account access": {},
"cre account list-key": {},
"cre init": {},
"cre generate-bindings": {},
Expand Down
6 changes: 6 additions & 0 deletions cmd/template/help_template.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ Use "{{.CommandPath}} [command] --help" for more information about a command.
to login into your cre account, then:
$ cre init
to create your first cre project.
{{- if needsDeployAccess}}

🔑 Ready to deploy? Run:
$ cre account access
to request deployment access.
{{- end}}

📘 Need more help?
Visit https://docs.chain.link/cre
Expand Down
16 changes: 16 additions & 0 deletions cmd/whoami/whoami.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ func (h *Handler) Execute(ctx context.Context) error {
return fmt.Errorf("graphql request failed: %w", err)
}

// Get deployment access status
deployAccess, err := h.credentials.GetDeploymentAccessStatus()
if err != nil {
h.log.Debug().Err(err).Msg("failed to get deployment access status")
}

fmt.Println("")
fmt.Println("Account details retrieved:")
fmt.Println("")
Expand All @@ -90,6 +96,16 @@ func (h *Handler) Execute(ctx context.Context) error {
}
fmt.Printf("\tOrganization ID: %s\n", respEnvelope.GetOrganization.OrganizationID)
fmt.Printf("\tOrganization Name: %s\n", respEnvelope.GetOrganization.DisplayName)

// Display deployment access status
if deployAccess != nil {
if deployAccess.HasAccess {
fmt.Printf("\tDeploy Access: Enabled\n")
} else {
fmt.Printf("\tDeploy Access: Not enabled (run 'cre account access' to request)\n")
}
}

fmt.Println("")

return nil
Expand Down
26 changes: 22 additions & 4 deletions cmd/workflow/deploy/deploy.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package deploy

import (
"context"
"errors"
"fmt"
"io"
Expand All @@ -13,6 +14,7 @@ import (
"github.com/spf13/viper"

"github.com/smartcontractkit/cre-cli/cmd/client"
"github.com/smartcontractkit/cre-cli/internal/accessrequest"
"github.com/smartcontractkit/cre-cli/internal/constants"
"github.com/smartcontractkit/cre-cli/internal/credentials"
"github.com/smartcontractkit/cre-cli/internal/environments"
Expand Down Expand Up @@ -62,6 +64,7 @@ type handler struct {
workflowArtifact *workflowArtifact
wrc *client.WorkflowRegistryV2Client
runtimeContext *runtime.Context
accessRequester *accessrequest.Requester

validated bool

Expand Down Expand Up @@ -94,7 +97,7 @@ func New(runtimeContext *runtime.Context) *cobra.Command {
if err := h.ValidateInputs(); err != nil {
return err
}
return h.Execute()
return h.Execute(cmd.Context())
},
}

Expand All @@ -118,10 +121,16 @@ func newHandler(ctx *runtime.Context, stdin io.Reader) *handler {
workflowArtifact: &workflowArtifact{},
wrc: nil,
runtimeContext: ctx,
accessRequester: accessrequest.NewRequester(ctx.Credentials, ctx.Logger, stdin),
validated: false,
wg: sync.WaitGroup{},
wrcErr: nil,
}

return &h
}

func (h *handler) initWorkflowRegistryClient() {
h.wg.Add(1)
go func() {
defer h.wg.Done()
Expand All @@ -132,8 +141,6 @@ func newHandler(ctx *runtime.Context, stdin io.Reader) *handler {
}
h.wrc = wrc
}()

return &h
}

func (h *handler) ResolveInputs(v *viper.Viper) (Inputs, error) {
Expand Down Expand Up @@ -177,7 +184,18 @@ func (h *handler) ValidateInputs() error {
return nil
}

func (h *handler) Execute() error {
func (h *handler) Execute(ctx context.Context) error {
deployAccess, err := h.credentials.GetDeploymentAccessStatus()
if err != nil {
return fmt.Errorf("failed to check deployment access: %w", err)
}

if !deployAccess.HasAccess {
return h.accessRequester.PromptAndSubmitRequest()
}

h.initWorkflowRegistryClient()

h.displayWorkflowDetails()

if err := h.Compile(); err != nil {
Expand Down
34 changes: 33 additions & 1 deletion cmd/workflow/simulate/simulate.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (

cmdcommon "github.com/smartcontractkit/cre-cli/cmd/common"
"github.com/smartcontractkit/cre-cli/internal/constants"
"github.com/smartcontractkit/cre-cli/internal/credentials"
"github.com/smartcontractkit/cre-cli/internal/runtime"
"github.com/smartcontractkit/cre-cli/internal/settings"
"github.com/smartcontractkit/cre-cli/internal/validation"
Expand Down Expand Up @@ -101,13 +102,15 @@ func New(runtimeContext *runtime.Context) *cobra.Command {
type handler struct {
log *zerolog.Logger
runtimeContext *runtime.Context
credentials *credentials.Credentials
validated bool
}

func newHandler(ctx *runtime.Context) *handler {
return &handler{
log: ctx.Logger,
runtimeContext: ctx,
credentials: ctx.Credentials,
validated: false,
}
}
Expand Down Expand Up @@ -332,7 +335,36 @@ func (h *handler) Execute(inputs Inputs) error {
// if logger instance is set to DEBUG, that means verbosity flag is set by the user
verbosity := h.log.GetLevel() == zerolog.DebugLevel

return run(ctx, wasmFileBinary, config, secrets, inputs, verbosity)
err = run(ctx, wasmFileBinary, config, secrets, inputs, verbosity)
if err != nil {
return err
}

h.showDeployAccessHint()

return nil
}

func (h *handler) showDeployAccessHint() {
if h.credentials == nil {
return
}

deployAccess, err := h.credentials.GetDeploymentAccessStatus()
if err != nil {
return
}

if !deployAccess.HasAccess {
fmt.Println("")
fmt.Println("─────────────────────────────────────────────────────────────")
fmt.Println("")
fmt.Println(" Simulation complete! Ready to deploy your workflow?")
fmt.Println("")
fmt.Println(" Run 'cre account access' to request deployment access.")
fmt.Println("")
fmt.Println("─────────────────────────────────────────────────────────────")
}
}

// run instantiates the engine, starts it and blocks until the context is canceled.
Expand Down
Loading
Loading