Skip to content
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Unreleased

## Enhancements

* Add variable set support for stacks with `ApplyToStacks`, `RemoveFromStacks`, and `UpdateStacks` API methods by @nithishravindra [#1251](https://github.com/hashicorp/go-tfe/pull/1251)

# v1.96.0

## Enhancements
Expand Down
4 changes: 4 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ var (

ErrRequiredProjectID = errors.New("project ID is required")

ErrRequiredStackID = errors.New("stack ID is required")

ErrWorkspacesRequired = errors.New("workspaces is required")

ErrWorkspaceMinLimit = errors.New("must provide at least one workspace")
Expand Down Expand Up @@ -379,6 +381,8 @@ var (

ErrRequiredWorkspacesList = errors.New("no workspaces list provided")

ErrRequiredStacksList = errors.New("no stacks list provided")

ErrCommentBody = errors.New("comment body is required")

ErrEmptyTeamName = errors.New("team name can not be empty")
Expand Down
43 changes: 43 additions & 0 deletions mocks/variable_set_mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

130 changes: 130 additions & 0 deletions variable_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,17 @@ type VariableSets interface {
// Remove variable set from projects in the supplied list.
RemoveFromProjects(ctx context.Context, variableSetID string, options VariableSetRemoveFromProjectsOptions) error

// Apply variable set to stacks in the supplied list.
ApplyToStacks(ctx context.Context, variableSetID string, options *VariableSetApplyToStacksOptions) error

// Remove variable set from stacks in the supplied list.
RemoveFromStacks(ctx context.Context, variableSetID string, options *VariableSetRemoveFromStacksOptions) error

// Update list of workspaces to which the variable set is applied to match the supplied list.
UpdateWorkspaces(ctx context.Context, variableSetID string, options *VariableSetUpdateWorkspacesOptions) (*VariableSet, error)

// Update list of stacks to which the variable set is applied to match the supplied list.
UpdateStacks(ctx context.Context, variableSetID string, options *VariableSetUpdateStacksOptions) (*VariableSet, error)
}

// variableSets implements VariableSets.
Expand Down Expand Up @@ -87,6 +96,7 @@ type VariableSet struct {
Parent *Parent `jsonapi:"polyrelation,parent"`
Workspaces []*Workspace `jsonapi:"relation,workspaces,omitempty"`
Projects []*Project `jsonapi:"relation,projects,omitempty"`
Stacks []*Stack `jsonapi:"relation,stacks,omitempty"`
Variables []*VariableSetVariable `jsonapi:"relation,vars,omitempty"`
}

Expand All @@ -97,6 +107,7 @@ type VariableSetIncludeOpt string
const (
VariableSetWorkspaces VariableSetIncludeOpt = "workspaces"
VariableSetProjects VariableSetIncludeOpt = "projects"
VariableSetStacks VariableSetIncludeOpt = "stacks"
VariableSetVars VariableSetIncludeOpt = "vars"
)

Expand Down Expand Up @@ -185,12 +196,24 @@ type VariableSetApplyToProjectsOptions struct {
Projects []*Project
}

// VariableSetApplyToStacksOptions represents the options for applying variable sets to stacks.
type VariableSetApplyToStacksOptions struct {
// The stacks to apply the variable set to (additive).
Stacks []*Stack
}

// VariableSetRemoveFromProjectsOptions represents the options for removing variable sets from projects.
type VariableSetRemoveFromProjectsOptions struct {
// The projects to remove the variable set from.
Projects []*Project
}

// VariableSetRemoveFromStacksOptions represents the options for removing variable sets from stacks.
type VariableSetRemoveFromStacksOptions struct {
// The stacks to remove the variable set from.
Stacks []*Stack
}

// VariableSetUpdateWorkspacesOptions represents a subset of update options specifically for applying variable sets to workspaces
type VariableSetUpdateWorkspacesOptions struct {
// Type is a public field utilized by JSON:API to
Expand All @@ -203,12 +226,30 @@ type VariableSetUpdateWorkspacesOptions struct {
Workspaces []*Workspace `jsonapi:"relation,workspaces"`
}

// VariableSetUpdateStacksOptions represents a subset of update options specifically for applying variable sets to stacks
type VariableSetUpdateStacksOptions struct {
// Type is a public field utilized by JSON:API to
// set the resource type via the field tag.
// It is not a user-defined value and does not need to be set.
// https://jsonapi.org/format/#crud-creating
Type string `jsonapi:"primary,varsets"`

// The stacks to be applied to. An empty set means remove all applied
Stacks []*Stack `jsonapi:"relation,stacks"`
}

type privateVariableSetUpdateWorkspacesOptions struct {
Type string `jsonapi:"primary,varsets"`
Global bool `jsonapi:"attr,global"`
Workspaces []*Workspace `jsonapi:"relation,workspaces"`
}

type privateVariableSetUpdateStacksOptions struct {
Type string `jsonapi:"primary,varsets"`
Global bool `jsonapi:"attr,global"`
Stacks []*Stack `jsonapi:"relation,stacks"`
}

// List all Variable Sets in the organization
func (s *variableSets) List(ctx context.Context, organization string, options *VariableSetListOptions) (*VariableSetList, error) {
if !validStringID(&organization) {
Expand Down Expand Up @@ -444,6 +485,42 @@ func (s variableSets) RemoveFromProjects(ctx context.Context, variableSetID stri
return req.Do(ctx, nil)
}

// ApplyToStacks applies the variable set to stacks in the supplied list.
// This method will return an error if the variable set has global = true.
func (s *variableSets) ApplyToStacks(ctx context.Context, variableSetID string, options *VariableSetApplyToStacksOptions) error {
if !validStringID(&variableSetID) {
return ErrInvalidVariableSetID
}
if err := options.valid(); err != nil {
return err
}

u := fmt.Sprintf("varsets/%s/relationships/stacks", url.PathEscape(variableSetID))
req, err := s.client.NewRequest("POST", u, options.Stacks)
if err != nil {
return err
}

return req.Do(ctx, nil)
}

func (s *variableSets) RemoveFromStacks(ctx context.Context, variableSetID string, options *VariableSetRemoveFromStacksOptions) error {
if !validStringID(&variableSetID) {
return ErrInvalidVariableSetID
}
if err := options.valid(); err != nil {
return err
}

u := fmt.Sprintf("varsets/%s/relationships/stacks", url.PathEscape(variableSetID))
req, err := s.client.NewRequest("DELETE", u, options.Stacks)
if err != nil {
return err
}

return req.Do(ctx, nil)
}

// Update variable set to be applied to only the workspaces in the supplied list.
func (s *variableSets) UpdateWorkspaces(ctx context.Context, variableSetID string, options *VariableSetUpdateWorkspacesOptions) (*VariableSet, error) {
if err := options.valid(); err != nil {
Expand Down Expand Up @@ -472,6 +549,34 @@ func (s *variableSets) UpdateWorkspaces(ctx context.Context, variableSetID strin
return v, nil
}

// Update variable set to be applied to only the stacks in the supplied list.
func (s *variableSets) UpdateStacks(ctx context.Context, variableSetID string, options *VariableSetUpdateStacksOptions) (*VariableSet, error) {
if err := options.valid(); err != nil {
return nil, err
}

// Use private struct to ensure global is set to false when applying to stacks
o := privateVariableSetUpdateStacksOptions{
Global: bool(false),
Stacks: options.Stacks,
}

// We force inclusion of stacks as that is the primary data for which we are concerned with confirming changes.
u := fmt.Sprintf("varsets/%s?include=%s", url.PathEscape(variableSetID), VariableSetStacks)
req, err := s.client.NewRequest("PATCH", u, &o)
if err != nil {
return nil, err
}

v := &VariableSet{}
err = req.Do(ctx, v)
if err != nil {
return nil, err
}

return v, nil
}

func (o *VariableSetListOptions) valid() error {
return nil
}
Expand Down Expand Up @@ -525,9 +630,34 @@ func (o VariableSetRemoveFromProjectsOptions) valid() error {
return nil
}

func (o VariableSetApplyToStacksOptions) valid() error {
for _, s := range o.Stacks {
if !validStringID(&s.ID) {
return ErrRequiredStackID
}
}
return nil
}

func (o VariableSetRemoveFromStacksOptions) valid() error {
for _, s := range o.Stacks {
if !validStringID(&s.ID) {
return ErrRequiredStackID
}
}
return nil
}

func (o *VariableSetUpdateWorkspacesOptions) valid() error {
if o == nil || o.Workspaces == nil {
return ErrRequiredWorkspacesList
}
return nil
}

func (o *VariableSetUpdateStacksOptions) valid() error {
if o == nil || o.Stacks == nil {
return ErrRequiredStacksList
}
return nil
}
Loading
Loading