Skip to content

Commit

Permalink
Add run confirmation and user provided metadata. (#14)
Browse files Browse the repository at this point in the history
* Add run confirmation and user provided metadata.

* Fix lint.

* Fix lint.

* Change to graphql fork.

* Fix passing request options.
  • Loading branch information
cube2222 authored May 17, 2021
1 parent 4df338d commit 550a49e
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 21 deletions.
8 changes: 4 additions & 4 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,22 @@ func New(wraps *http.Client, session session.Session) Client {
return &client{wraps: wraps, session: session}
}

func (c *client) Mutate(ctx context.Context, mutation interface{}, variables map[string]interface{}) error {
func (c *client) Mutate(ctx context.Context, mutation interface{}, variables map[string]interface{}, opts ...graphql.RequestOption) error {
apiClient, err := c.apiClient(ctx)
if err != nil {
return nil
}

return apiClient.Mutate(ctx, mutation, variables)
return apiClient.Mutate(ctx, mutation, variables, opts...)
}

func (c *client) Query(ctx context.Context, query interface{}, variables map[string]interface{}) error {
func (c *client) Query(ctx context.Context, query interface{}, variables map[string]interface{}, opts ...graphql.RequestOption) error {
apiClient, err := c.apiClient(ctx)
if err != nil {
return nil
}

return apiClient.Query(ctx, query, variables)
return apiClient.Query(ctx, query, variables, opts...)
}

func (c *client) URL(format string, a ...interface{}) string {
Expand Down
10 changes: 7 additions & 3 deletions client/interface.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package client

import "context"
import (
"context"

"github.com/shurcooL/graphql"
)

// Client abstracts away Spacelift's client API.
type Client interface {
// Query executes a single GraphQL query request.
Query(context.Context, interface{}, map[string]interface{}) error
Query(context.Context, interface{}, map[string]interface{}, ...graphql.RequestOption) error

// Mutate executes a single GraphQL mutation request.
Mutate(context.Context, interface{}, map[string]interface{}) error
Mutate(context.Context, interface{}, map[string]interface{}, ...graphql.RequestOption) error

// URL returns a full URL given a formatted path.
URL(string, ...interface{}) string
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ require (
github.com/sabhiram/go-gitignore v0.0.0-20201211210132-54b8a0bf510f
github.com/shurcooL/graphql v0.0.0-20200928012149-18c5c3165e3a
github.com/urfave/cli/v2 v2.3.0
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602
golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750 // indirect
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72
)

replace github.com/mholt/archiver/v3 => github.com/spacelift-io/archiver/v3 v3.3.1-0.20210427125142-c305b5a627ba

replace github.com/shurcooL/graphql => github.com/marcinwyszynski/graphql v0.0.0-20210505073322-ed22d920d37d
17 changes: 10 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/gookit/color v1.4.1/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/graph-gophers/graphql-go v1.1.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
Expand All @@ -141,6 +142,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/marcinwyszynski/graphql v0.0.0-20210505073322-ed22d920d37d h1:9Z8P/yiZQQucF5Yo3bmn0JD7Y4TrtGETsbmZpexIuxc=
github.com/marcinwyszynski/graphql v0.0.0-20210505073322-ed22d920d37d/go.mod h1:arY+KAJGvLcmVrvOSx+bDyXcfKl4+eurb19qg+FYX08=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
Expand All @@ -157,6 +160,7 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.11.0 h1:+CqWgvj0OZycCaqclBD1pxKHAU+tOkHmQIWvDHq2aug=
github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand All @@ -172,8 +176,6 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sabhiram/go-gitignore v0.0.0-20201211210132-54b8a0bf510f h1:8P2MkG70G76gnZBOPGwmMIgwBb/rESQuwsJ7K8ds4NE=
github.com/sabhiram/go-gitignore v0.0.0-20201211210132-54b8a0bf510f/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
github.com/shurcooL/graphql v0.0.0-20200928012149-18c5c3165e3a h1:KikTa6HtAK8cS1qjvUvvq4QO21QnwC+EfvB+OAuZ/ZU=
github.com/shurcooL/graphql v0.0.0-20200928012149-18c5c3165e3a/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/spacelift-io/archiver/v3 v3.3.1-0.20210427125142-c305b5a627ba h1:EKGvn71p8gFSqPzn/cPTbSFAOIa7z+3TmZuO6M/EWBU=
Expand Down Expand Up @@ -262,8 +264,8 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 h1:Ugb8sMTWuWRC3+sz5WeN/4kejDx9BvIwnPUiJBjJE+8=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand Down Expand Up @@ -312,8 +314,8 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750 h1:ZBu6861dZq7xBnG1bn5SRU0vA8nx42at4+kP07FMTog=
golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 h1:VqE9gduFZ4dbR7XoL77lHFp0/DyDUBKSXK7CMFkVcV0=
Expand All @@ -322,8 +324,9 @@ golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fq
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down
5 changes: 5 additions & 0 deletions internal/cmd/stack/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package stack

// UserProvidedRunMetadataHeader is the HTTP header used to pass arbitrary metadata
// to runs when creating or confirming them.
const UserProvidedRunMetadataHeader = "Spacelift-User-Provided-Run-Metadata"
5 changes: 5 additions & 0 deletions internal/cmd/stack/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ var flagNoInit = &cli.BoolFlag{
Value: false,
}

var flagRunMetadata = &cli.StringFlag{
Name: "run-metadata",
Usage: "Additional opaque metadata you will be able to access from policies handling this Run.",
}

var flagTail = &cli.BoolFlag{
Name: "tail",
Usage: "Indicate whether to tail the run",
Expand Down
12 changes: 9 additions & 3 deletions internal/cmd/stack/local_preview.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import (
"github.com/mholt/archiver/v3"
ignore "github.com/sabhiram/go-gitignore"
"github.com/shurcooL/graphql"
"github.com/spacelift-io/spacectl/internal/cmd/authenticated"
"github.com/urfave/cli/v2"

"github.com/spacelift-io/spacectl/internal/cmd/authenticated"
)

func localPreview() cli.ActionFunc {
Expand Down Expand Up @@ -62,11 +63,16 @@ func localPreview() cli.ActionFunc {
}

triggerVariables := map[string]interface{}{
"stack": graphql.ID(stackID),
"stack": graphql.ID(stackID),
"workspace": graphql.ID(uploadMutation.UploadLocalWorkspace.ID),
}

if err := authenticated.Client.Mutate(ctx, &triggerMutation, triggerVariables); err != nil {
var requestOpts []graphql.RequestOption
if cliCtx.IsSet(flagRunMetadata.Name) {
requestOpts = append(requestOpts, graphql.WithHeader(UserProvidedRunMetadataHeader, cliCtx.String(flagRunMetadata.Name)))
}

if err := authenticated.Client.Mutate(ctx, &triggerMutation, triggerVariables, requestOpts...); err != nil {
return err
}

Expand Down
56 changes: 56 additions & 0 deletions internal/cmd/stack/run_confirm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package stack

import (
"context"
"fmt"

"github.com/shurcooL/graphql"
"github.com/urfave/cli/v2"

"github.com/spacelift-io/spacectl/internal/cmd/authenticated"
)

func runConfirm() cli.ActionFunc {
return func(cliCtx *cli.Context) error {
var mutation struct {
RunConfirm struct {
ID string `grapqhl:"id"`
} `graphql:"runConfirm(stack: $stack, run: $run)"`
}

variables := map[string]interface{}{
"stack": graphql.ID(stackID),
"run": graphql.ID(cliCtx.String(flagRun.Name)),
}

ctx := context.Background()

var requestOpts []graphql.RequestOption
if cliCtx.IsSet(flagRunMetadata.Name) {
requestOpts = append(requestOpts, graphql.WithHeader(UserProvidedRunMetadataHeader, cliCtx.String(flagRunMetadata.Name)))
}

if err := authenticated.Client.Mutate(ctx, &mutation, variables, requestOpts...); err != nil {
return err
}

fmt.Println("You have successfully confirmed a deployment")

fmt.Println("The live run can be visited at", authenticated.Client.URL(
"/stack/%s/run/%s",
stackID,
mutation.RunConfirm.ID,
))

if !cliCtx.Bool(flagTail.Name) {
return nil
}

terminal, err := runLogs(ctx, stackID, mutation.RunConfirm.ID)
if err != nil {
return err
}

return terminal.Error()
}
}
7 changes: 6 additions & 1 deletion internal/cmd/stack/run_trigger.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ func runTrigger(spaceliftType, humanType string) cli.ActionFunc {

ctx := context.Background()

if err := authenticated.Client.Mutate(ctx, &mutation, variables); err != nil {
var requestOpts []graphql.RequestOption
if cliCtx.IsSet(flagRunMetadata.Name) {
requestOpts = append(requestOpts, graphql.WithHeader(UserProvidedRunMetadataHeader, cliCtx.String(flagRunMetadata.Name)))
}

if err := authenticated.Client.Mutate(ctx, &mutation, variables, requestOpts...); err != nil {
return err
}

Expand Down
15 changes: 15 additions & 0 deletions internal/cmd/stack/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,24 @@ func Command() *cli.Command {
Flags: []cli.Flag{flagStackID},
Before: actions.Multi(authenticated.Ensure, beforeEach),
Subcommands: []*cli.Command{
{
Category: "Run management",
Name: "confirm",
Usage: "Confirm an unconfirmed tracked run",
Flags: []cli.Flag{
flagRun,
flagRunMetadata,
flagTail,
},
Action: runConfirm(),
},
{
Category: "Run management",
Name: "deploy",
Usage: "Start a deployment (tracked run)",
Flags: []cli.Flag{
flagCommitSHA,
flagRunMetadata,
flagTail,
},
Action: runTrigger("TRACKED", "deployment"),
Expand All @@ -32,6 +44,7 @@ func Command() *cli.Command {
Name: "local-preview",
Usage: "Start a preview (proposed run) based on the current directory. Respects .gitignore and .terraformignore.",
Flags: []cli.Flag{
flagRunMetadata,
flagNoTail,
},
Action: localPreview(),
Expand All @@ -52,6 +65,7 @@ func Command() *cli.Command {
Usage: "Start a preview (proposed run)",
Flags: []cli.Flag{
flagCommitSHA,
flagRunMetadata,
flagTail,
},
Action: runTrigger("PROPOSED", "preview"),
Expand All @@ -69,6 +83,7 @@ func Command() *cli.Command {
Usage: "Perform a task in a workspace",
Flags: []cli.Flag{
flagNoInit,
flagRunMetadata,
flagTail,
},
Action: taskCommand,
Expand Down
7 changes: 6 additions & 1 deletion internal/cmd/stack/task_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ func taskCommand(cliCtx *cli.Context) error {

ctx := context.Background()

if err := authenticated.Client.Mutate(ctx, &mutation, variables); err != nil {
var requestOpts []graphql.RequestOption
if cliCtx.IsSet(flagRunMetadata.Name) {
requestOpts = append(requestOpts, graphql.WithHeader(UserProvidedRunMetadataHeader, cliCtx.String(flagRunMetadata.Name)))
}

if err := authenticated.Client.Mutate(ctx, &mutation, variables, requestOpts...); err != nil {
return err
}

Expand Down

0 comments on commit 550a49e

Please sign in to comment.