diff --git a/organization.go b/organization.go index 1a4e7da64..7c17ea885 100644 --- a/organization.go +++ b/organization.go @@ -113,6 +113,7 @@ type OrganizationPermissions struct { CanCreateWorkspace bool `jsonapi:"attr,can-create-workspace"` CanCreateWorkspaceMigration bool `jsonapi:"attr,can-create-workspace-migration"` CanDestroy bool `jsonapi:"attr,can-destroy"` + CanManageRunTasks bool `jsonapi:"attr,can-manage-run-tasks"` CanTraverse bool `jsonapi:"attr,can-traverse"` CanUpdate bool `jsonapi:"attr,can-update"` CanUpdateAPIToken bool `jsonapi:"attr,can-update-api-token"` diff --git a/organization_integration_test.go b/organization_integration_test.go index e097b6470..10cafc305 100644 --- a/organization_integration_test.go +++ b/organization_integration_test.go @@ -459,3 +459,26 @@ func TestOrganization_Unmarshal(t *testing.T) { assert.NotEmpty(t, org.Permissions) assert.Equal(t, org.Permissions.CanCreateTeam, true) } + +func TestOrganizationsReadRunTasksPermission(t *testing.T) { + skipIfFreeOnly(t) + skipIfBeta(t) + skipIfEnterprise(t) + + client := testClient(t) + ctx := context.Background() + + orgTest, orgTestCleanup := createOrganization(t, client) + defer orgTestCleanup() + + t.Run("when the org exists", func(t *testing.T) { + org, err := client.Organizations.Read(ctx, orgTest.Name) + require.NoError(t, err) + assert.Equal(t, orgTest, org) + assert.NotEmpty(t, org.Permissions) + + t.Run("permissions are properly decoded", func(t *testing.T) { + assert.True(t, org.Permissions.CanManageRunTasks) + }) + }) +} diff --git a/team.go b/team.go index 92d92a160..aa4a8a6a6 100644 --- a/team.go +++ b/team.go @@ -64,6 +64,7 @@ type OrganizationAccess struct { ManageVCSSettings bool `jsonapi:"attr,manage-vcs-settings"` ManageProviders bool `jsonapi:"attr,manage-providers"` ManageModules bool `jsonapi:"attr,manage-modules"` + ManageRunTasks bool `jsonapi:"attr,manage-run-tasks"` } // TeamPermissions represents the current user's permissions on the team. @@ -139,6 +140,7 @@ type OrganizationAccessOptions struct { ManageVCSSettings *bool `json:"manage-vcs-settings,omitempty"` ManageProviders *bool `json:"manage-providers,omitempty"` ManageModules *bool `json:"manage-modules,omitempty"` + ManageRunTasks *bool `json:"manage-run-tasks,omitempty"` } // List all the teams of the given organization. diff --git a/team_access.go b/team_access.go index 2a54f458e..7496cce53 100644 --- a/team_access.go +++ b/team_access.go @@ -98,6 +98,7 @@ type TeamAccess struct { StateVersions StateVersionsPermissionType `jsonapi:"attr,state-versions"` SentinelMocks SentinelMocksPermissionType `jsonapi:"attr,sentinel-mocks"` WorkspaceLocking bool `jsonapi:"attr,workspace-locking"` + RunTasks bool `jsonapi:"attr,run-tasks"` // Relations Team *Team `jsonapi:"relation,team"` @@ -154,6 +155,7 @@ type TeamAccessUpdateOptions struct { StateVersions *StateVersionsPermissionType `jsonapi:"attr,state-versions,omitempty"` SentinelMocks *SentinelMocksPermissionType `jsonapi:"attr,sentinel-mocks,omitempty"` WorkspaceLocking *bool `jsonapi:"attr,workspace-locking,omitempty"` + RunTasks *bool `jsonapi:"attr,run-tasks,omitempty"` } // List all the team accesses for a given workspace. diff --git a/team_access_integration_test.go b/team_access_integration_test.go index cb9197707..ae2728e67 100644 --- a/team_access_integration_test.go +++ b/team_access_integration_test.go @@ -338,3 +338,68 @@ func TestTeamAccessesRemove(t *testing.T) { assert.Equal(t, err, ErrInvalidAccessTeamID) }) } + +func TestTeamAccessesReadRunTasks(t *testing.T) { + skipIfFreeOnly(t) + skipIfBeta(t) + skipIfEnterprise(t) + + client := testClient(t) + ctx := context.Background() + + orgTest, orgTestCleanup := createOrganization(t, client) + defer orgTestCleanup() + wTest, wTestCleanup := createWorkspace(t, client, orgTest) + defer wTestCleanup() + tmTest, tmTestCleanup := createTeam(t, client, orgTest) + defer tmTestCleanup() + + taTest, taTestCleanup := createTeamAccess(t, client, tmTest, wTest, orgTest) + defer taTestCleanup() + + t.Run("when the team access exists", func(t *testing.T) { + ta, err := client.TeamAccess.Read(ctx, taTest.ID) + require.NoError(t, err) + + assert.Equal(t, AccessAdmin, ta.Access) + + t.Run("permission attributes are decoded", func(t *testing.T) { + assert.Equal(t, true, ta.RunTasks) + }) + }) +} + +func TestTeamAccessesUpdateRunTasks(t *testing.T) { + skipIfFreeOnly(t) + skipIfBeta(t) + skipIfEnterprise(t) + + client := testClient(t) + ctx := context.Background() + + orgTest, orgTestCleanup := createOrganization(t, client) + defer orgTestCleanup() + + wTest, wTestCleanup := createWorkspace(t, client, orgTest) + defer wTestCleanup() + + tmTest, tmTestCleanup := createTeam(t, client, orgTest) + defer tmTestCleanup() + + taTest, taTestCleanup := createTeamAccess(t, client, tmTest, wTest, orgTest) + defer taTestCleanup() + + t.Run("with valid attributes", func(t *testing.T) { + newAccess := !taTest.RunTasks + options := TeamAccessUpdateOptions{ + Access: Access(AccessCustom), + RunTasks: &newAccess, + } + + ta, err := client.TeamAccess.Update(ctx, taTest.ID, options) + require.NoError(t, err) + + assert.Equal(t, AccessCustom, ta.Access) + assert.Equal(t, newAccess, ta.RunTasks) + }) +} diff --git a/team_integration_test.go b/team_integration_test.go index 0d8423029..83149409e 100644 --- a/team_integration_test.go +++ b/team_integration_test.go @@ -350,3 +350,45 @@ func TestTeamCreateOptions_Marshal(t *testing.T) { ` assert.Equal(t, expectedBody, string(bodyBytes)) } + +func TestTeamsUpdateRunTasks(t *testing.T) { + skipIfFreeOnly(t) + skipIfBeta(t) + skipIfEnterprise(t) + + client := testClient(t) + ctx := context.Background() + + orgTest, orgTestCleanup := createOrganization(t, client) + defer orgTestCleanup() + + tmTest, tmTestCleanup := createTeam(t, client, orgTest) + defer tmTestCleanup() + + t.Run("with valid options", func(t *testing.T) { + options := TeamUpdateOptions{ + Name: String("foo bar"), + OrganizationAccess: &OrganizationAccessOptions{ + ManageRunTasks: Bool(true), + }, + Visibility: String("organization"), + } + + tm, err := client.Teams.Update(ctx, tmTest.ID, options) + require.NoError(t, err) + + refreshed, err := client.Teams.Read(ctx, tmTest.ID) + require.NoError(t, err) + + for _, item := range []*Team{ + tm, + refreshed, + } { + assert.Equal(t, *options.Name, item.Name) + assert.Equal(t, + *options.OrganizationAccess.ManageRunTasks, + item.OrganizationAccess.ManageRunTasks, + ) + } + }) +} diff --git a/workspace.go b/workspace.go index 0f58e4ab5..e4200eb85 100644 --- a/workspace.go +++ b/workspace.go @@ -193,6 +193,7 @@ type WorkspacePermissions struct { CanDestroy bool `jsonapi:"attr,can-destroy"` CanForceUnlock bool `jsonapi:"attr,can-force-unlock"` CanLock bool `jsonapi:"attr,can-lock"` + CanManageRunTasks bool `jsonapi:"attr,can-manage-run-tasks"` CanQueueApply bool `jsonapi:"attr,can-queue-apply"` CanQueueDestroy bool `jsonapi:"attr,can-queue-destroy"` CanQueueRun bool `jsonapi:"attr,can-queue-run"` diff --git a/workspace_integration_test.go b/workspace_integration_test.go index e4e53add8..fd6eb145a 100644 --- a/workspace_integration_test.go +++ b/workspace_integration_test.go @@ -1411,3 +1411,25 @@ func TestWorkspaceCreateOptions_Marshal(t *testing.T) { ` assert.Equal(t, expectedBody, string(bodyBytes)) } + +func TestWorkspacesRunTasksPermission(t *testing.T) { + skipIfFreeOnly(t) + skipIfBeta(t) + skipIfEnterprise(t) + + client := testClient(t) + ctx := context.Background() + + orgTest, orgTestCleanup := createOrganization(t, client) + defer orgTestCleanup() + + wTest, wTestCleanup := createWorkspace(t, client, orgTest) + defer wTestCleanup() + + t.Run("when the workspace exists", func(t *testing.T) { + w, err := client.Workspaces.Read(ctx, orgTest.Name, wTest.Name) + require.NoError(t, err) + assert.Equal(t, wTest, w) + assert.True(t, w.Permissions.CanManageRunTasks) + }) +}