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 support for listing effective tag bindings for a workspace or project by @brandonc

# v1.69.0

## Enhancements
Expand Down
15 changes: 15 additions & 0 deletions mocks/project_mocks.go

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

15 changes: 15 additions & 0 deletions mocks/workspace_mocks.go

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

29 changes: 29 additions & 0 deletions project.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ type Projects interface {
// ListTagBindings lists all tag bindings associated with the project.
ListTagBindings(ctx context.Context, projectID string) ([]*TagBinding, error)

// ListEffectiveTagBindings lists all tag bindings associated with the project. In practice,
// this should be the same as ListTagBindings since projects do not currently inherit
// tag bindings.
ListEffectiveTagBindings(ctx context.Context, workspaceID string) ([]*EffectiveTagBinding, error)

// AddTagBindings adds or modifies the value of existing tag binding keys for a project.
AddTagBindings(ctx context.Context, projectID string, options ProjectAddTagBindingsOptions) ([]*TagBinding, error)
}
Expand Down Expand Up @@ -218,6 +223,30 @@ func (s *projects) ListTagBindings(ctx context.Context, projectID string) ([]*Ta
return list.Items, nil
}

func (s *projects) ListEffectiveTagBindings(ctx context.Context, projectID string) ([]*EffectiveTagBinding, error) {
if !validStringID(&projectID) {
return nil, ErrInvalidProjectID
}

u := fmt.Sprintf("projects/%s/effective-tag-bindings", url.PathEscape(projectID))
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, err
}

var list struct {
*Pagination
Items []*EffectiveTagBinding
}

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

return list.Items, nil
}

// AddTagBindings adds or modifies the value of existing tag binding keys for a project
func (s *projects) AddTagBindings(ctx context.Context, projectID string, options ProjectAddTagBindingsOptions) ([]*TagBinding, error) {
if !validStringID(&projectID) {
Expand Down
41 changes: 40 additions & 1 deletion projects_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func TestProjectsUpdate(t *testing.T) {

t.Run("with valid options", func(t *testing.T) {
kBefore, kTestCleanup := createProject(t, client, orgTest)
defer kTestCleanup()
t.Cleanup(kTestCleanup)

kAfter, err := client.Projects.Update(ctx, kBefore.ID, ProjectUpdateOptions{
Name: String("new project name"),
Expand All @@ -226,6 +226,45 @@ func TestProjectsUpdate(t *testing.T) {
assert.Len(t, bindings, 1)
assert.Equal(t, "foo", bindings[0].Key)
assert.Equal(t, "bar", bindings[0].Value)

effectiveBindings, err := client.Projects.ListEffectiveTagBindings(ctx, kAfter.ID)
require.NoError(t, err)

assert.Len(t, effectiveBindings, 1)
assert.Equal(t, "foo", effectiveBindings[0].Key)
assert.Equal(t, "bar", effectiveBindings[0].Value)

ws, err := client.Workspaces.Create(ctx, orgTest.Name, WorkspaceCreateOptions{
Name: String("new-workspace-inherits-tags"),
Project: kAfter,
TagBindings: []*TagBinding{
{Key: "baz", Value: "qux"},
},
})
require.NoError(t, err)

t.Cleanup(func() {
err := client.Workspaces.DeleteByID(ctx, ws.ID)
if err != nil {
t.Errorf("Error destroying workspace! WARNING: Dangling resources\n"+
"may exist! The full error is shown below.\n\n"+
"Error: %s", err)
}
})

wsEffectiveBindings, err := client.Workspaces.ListEffectiveTagBindings(ctx, ws.ID)
require.NoError(t, err)

assert.Len(t, wsEffectiveBindings, 2)
for _, b := range wsEffectiveBindings {
if b.Key == "foo" {
assert.Equal(t, "bar", b.Value)
} else if b.Key == "baz" {
assert.Equal(t, "qux", b.Value)
} else {
assert.Fail(t, "unexpected tag binding %q", b.Key)
}
}
}
})

Expand Down
6 changes: 6 additions & 0 deletions tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ type TagBinding struct {
Value string `jsonapi:"attr,value,omitempty"`
}

type EffectiveTagBinding struct {
ID string `jsonapi:"primary,effective-tag-bindings"`
Key string `jsonapi:"attr,key"`
Value string `jsonapi:"attr,value,omitempty"`
}

func encodeTagFiltersAsParams(filters []*TagBinding) map[string][]string {
if len(filters) == 0 {
return nil
Expand Down
28 changes: 28 additions & 0 deletions workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ type Workspaces interface {
// ListTagBindings lists all tag bindings associated with the workspace.
ListTagBindings(ctx context.Context, workspaceID string) ([]*TagBinding, error)

// ListEffectiveTagBindings lists all tag bindings associated with the workspace which may be
// either inherited from a project or binded to the workspace itself.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/binded/bound/

ListEffectiveTagBindings(ctx context.Context, workspaceID string) ([]*EffectiveTagBinding, error)

// AddTagBindings adds or modifies the value of existing tag binding keys for a workspace.
AddTagBindings(ctx context.Context, workspaceID string, options WorkspaceAddTagBindingsOptions) ([]*TagBinding, error)
}
Expand Down Expand Up @@ -769,6 +773,30 @@ func (s *workspaces) ListTagBindings(ctx context.Context, workspaceID string) ([
return list.Items, nil
}

func (s *workspaces) ListEffectiveTagBindings(ctx context.Context, workspaceID string) ([]*EffectiveTagBinding, error) {
if !validStringID(&workspaceID) {
return nil, ErrInvalidWorkspaceID
}

u := fmt.Sprintf("workspaces/%s/effective-tag-bindings", url.PathEscape(workspaceID))
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, err
}

var list struct {
*Pagination
Items []*EffectiveTagBinding
}

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

return list.Items, nil
}

// AddTagBindings adds or modifies the value of existing tag binding keys for a workspace.
func (s *workspaces) AddTagBindings(ctx context.Context, workspaceID string, options WorkspaceAddTagBindingsOptions) ([]*TagBinding, error) {
if !validStringID(&workspaceID) {
Expand Down
7 changes: 7 additions & 0 deletions workspace_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1373,6 +1373,13 @@ func TestWorkspacesUpdate(t *testing.T) {
assert.Len(t, bindings, 1)
assert.Equal(t, "foo", bindings[0].Key)
assert.Equal(t, "bar", bindings[0].Value)

effectiveBindings, err := client.Workspaces.ListEffectiveTagBindings(ctx, wTest.ID)
require.NoError(t, err)

assert.Len(t, effectiveBindings, 1)
assert.Equal(t, "foo", effectiveBindings[0].Key)
assert.Equal(t, "bar", effectiveBindings[0].Value)
}
})

Expand Down
Loading