Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add approval and rejection support #82

Merged
merged 2 commits into from
Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
12 changes: 12 additions & 0 deletions client/enums/run_review_decision.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package enums

// RunReviewDecision represents the API RunReviewDecision enum.
type RunReviewDecision string

const (
// RunReviewDecisionApprove represents an approval decision.
RunReviewDecisionApprove = "APPROVE"

// RunReviewDecisionReject represents a rejection decision.
RunReviewDecisionReject = "REJECT"
)
7 changes: 6 additions & 1 deletion internal/cmd/stack/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,17 @@ var flagRequiredCommitSHA = &cli.StringFlag{
Required: true,
}

var flagRun = &cli.StringFlag{
var flagRequiredRun = &cli.StringFlag{
Name: "run",
Usage: "[Required] `ID` of the run",
Required: true,
}

var flagRun = &cli.StringFlag{
Name: "run",
Usage: "`ID` of the run",
}

var flagNoInit = &cli.BoolFlag{
Name: "noinit",
Usage: "Indicate whether to skip initialization for a task",
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/stack/run_confirm.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func runConfirm() cli.ActionFunc {

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

ctx := context.Background()
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/stack/run_discard.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func runDiscard() cli.ActionFunc {

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

ctx := context.Background()
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/stack/run_retry.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

func runRetry(cliCtx *cli.Context) error {
stackID := cliCtx.String(flagStackID.Name)
runID := cliCtx.String(flagRun.Name)
runID := cliCtx.String(flagRequiredRun.Name)

var mutation struct {
RunRetry struct {
Expand Down
64 changes: 64 additions & 0 deletions internal/cmd/stack/run_review.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package stack

import (
"context"
"fmt"

"github.com/shurcooL/graphql"
adamconnelly marked this conversation as resolved.
Show resolved Hide resolved
"github.com/spacelift-io/spacectl/client/enums"
"github.com/spacelift-io/spacectl/internal/cmd/authenticated"
"github.com/urfave/cli/v2"
)

type runReviewMutation struct {
Review struct {
ID string `graphql:"id"`
} `graphql:"runReview(stack: $stack, run: $run, decision: $decision, note: $note)"`
}

var flagRunReviewNote = &cli.StringFlag{
Name: "note",
Usage: "Description of why the review decision was made.",
Required: false,
}

func runApprove(cliCtx *cli.Context) error {
stackID := cliCtx.String(flagStackID.Name)
runID := cliCtx.String(flagRequiredRun.Name)
note := cliCtx.String(flagRunReviewNote.Name)

if nArgs := cliCtx.NArg(); nArgs != 0 {
return fmt.Errorf("expected zero arguments but got %d", nArgs)
}

return addRunReview(cliCtx.Context, stackID, runID, note, enums.RunReviewDecisionApprove)
}

func runReject(cliCtx *cli.Context) error {
stackID := cliCtx.String(flagStackID.Name)
runID := cliCtx.String(flagRequiredRun.Name)
note := cliCtx.String(flagRunReviewNote.Name)

if nArgs := cliCtx.NArg(); nArgs != 0 {
return fmt.Errorf("expected zero arguments but got %d", nArgs)
}

return addRunReview(cliCtx.Context, stackID, runID, note, enums.RunReviewDecisionReject)
}

func addRunReview(ctx context.Context, stackID, runID, note string, decision enums.RunReviewDecision) error {
var runIDGQL *graphql.ID
if runID != "" {
runIDGQL = graphql.NewID(runID)
}

var mutation runReviewMutation
variables := map[string]interface{}{
"stack": graphql.ID(stackID),
"run": runIDGQL,
"decision": decision,
"note": graphql.String(note),
}

return authenticated.Client.Mutate(ctx, &mutation, variables)
}
36 changes: 31 additions & 5 deletions internal/cmd/stack/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func Command() *cli.Command {
Usage: "Confirm an unconfirmed tracked run",
Flags: []cli.Flag{
flagStackID,
flagRun,
flagRequiredRun,
flagRunMetadata,
flagTail,
},
Expand All @@ -35,13 +35,39 @@ func Command() *cli.Command {
Usage: "Discard an unconfirmed tracked run",
Flags: []cli.Flag{
flagStackID,
flagRun,
flagRequiredRun,
flagTail,
},
Action: runDiscard(),
Before: authenticated.Ensure,
ArgsUsage: cmd.EmptyArgsUsage,
},
{
Category: "Run management",
Name: "approve",
Usage: "Approves a run or task. If no run is specified, the approval will be added to the current stack blocker.",
Flags: []cli.Flag{
flagStackID,
flagRun,
flagRunReviewNote,
},
Action: runApprove,
Before: authenticated.Ensure,
ArgsUsage: cmd.EmptyArgsUsage,
},
{
Category: "Run management",
Name: "reject",
Usage: "Rejects a run or task. If no run is specified, the rejection will be added to the current stack blocker.",
Flags: []cli.Flag{
flagStackID,
flagRun,
flagRunReviewNote,
},
Action: runReject,
Before: authenticated.Ensure,
ArgsUsage: cmd.EmptyArgsUsage,
},
{
Category: "Run management",
Name: "deploy",
Expand All @@ -62,7 +88,7 @@ func Command() *cli.Command {
Usage: "Retry a failed run",
Flags: []cli.Flag{
flagStackID,
flagRun,
flagRequiredRun,
flagTail,
},
Action: runRetry,
Expand Down Expand Up @@ -100,11 +126,11 @@ func Command() *cli.Command {
Usage: "Show logs for a particular run",
Flags: []cli.Flag{
flagStackID,
flagRun,
flagRequiredRun,
},
Action: func(cliCtx *cli.Context) error {
stackID := cliCtx.String(flagStackID.Name)
_, err := runLogs(context.Background(), stackID, cliCtx.String(flagRun.Name))
_, err := runLogs(context.Background(), stackID, cliCtx.String(flagRequiredRun.Name))
return err
},
Before: authenticated.Ensure,
Expand Down
5 changes: 4 additions & 1 deletion specs/spacectl-to-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,11 @@ We should support the following commands for working with Stacks:
- [ ] `delete` - deletes a stack
- [x] `show` - outputs information about a specified Stack
- [ ] `edit` - edits the name, labels and description for the stack
- [ ] `set-current-commit` - sets the current commit for the stack
- [x] `set-current-commit` - sets the current commit for the stack
- [x] `confirm` - confirms a run awaiting approval
- [x] `discard` - discards a run awaiting approval
- [x] `approve` - approves a run or task
- [x] `reject` - rejects a run or task
- [x] `deploy` - triggers a tracked (i.e. deployment) run
- [x] `preview` - triggers a preview run for a specific commit
- [x] `local-preview` - triggers a local-preview run using the current directory as the workspace
Expand Down