Skip to content

Commit

Permalink
Merge pull request #86 from jfrog/GH-85-add-project-role-resource
Browse files Browse the repository at this point in the history
Add project role resource
  • Loading branch information
alexhung authored Sep 25, 2023
2 parents c288f28 + 63816df commit 7043940
Show file tree
Hide file tree
Showing 16 changed files with 963 additions and 346 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## 1.3.0 (September 25, 2023). Tested on Artifactory 7.68.11 and Xray 3.82.11

FEATURES:
* **New Resource:** `project_role` - Separate resource to manage project role.
* resource/project: Add `use_project_role_resource` attribute to toggle if `project` resource should use its `roles` or not to manage project roles. Should be set to `true` when using in conjunction with `project_role` resource.

Issue: [#85](https://github.com/jfrog/terraform-provider-project/issues/85)
PR: [#86](https://github.com/jfrog/terraform-provider-project/pull/86)

## 1.2.1 (August 30, 2023). Tested on Artifactory 7.63.14 and Xray 3.80.9

IMPROVEMENTS:
Expand Down
5 changes: 3 additions & 2 deletions docs/resources/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ page_title: "project_environment Resource - terraform-provider-project"
subcategory: ""
description: |-
Creates a new environment for the specified project.
~>Note The combined length of project_key and name (separated by '-') cannot not exceeds 32 characters.
~>The combined length of project_key and name (separated by '-') cannot not exceeds 32 characters.
---

# project_environment (Resource)

Creates a new environment for the specified project.
~>**Note** The combined length of `project_key` and `name` (separated by '-') cannot not exceeds 32 characters.

~>The combined length of `project_key` and `name` (separated by '-') cannot not exceeds 32 characters.

## Example Usage

Expand Down
3 changes: 2 additions & 1 deletion docs/resources/project.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ lifecycle {
]
}
```
- `role` (Block Set) Project role. Element has one to one mapping with the [JFrog Project Roles API](https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-AddaNewRole) (see [below for nested schema](#nestedblock--role))
- `role` (Block Set, Deprecated) Project role. Element has one to one mapping with the [JFrog Project Roles API](https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-AddaNewRole) (see [below for nested schema](#nestedblock--role))
- `use_project_role_resource` (Boolean) When set to true, this resource will ignore the `roles` attributes and allow roles to be managed by `project_role` resource instead. Default to false.

### Read-Only

Expand Down
28 changes: 28 additions & 0 deletions docs/resources/role.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "project_role Resource - terraform-provider-project"
subcategory: ""
description: |-
Create a project role. Element has one to one mapping with the JFrog Project Roles API https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-AddaNewRole. Requires a user assigned with the 'Administer the Platform' role or Project Admin permissions if admin_privileges.manage_resoures is enabled.
---

# project_role (Resource)

Create a project role. Element has one to one mapping with the [JFrog Project Roles API](https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-AddaNewRole). Requires a user assigned with the 'Administer the Platform' role or Project Admin permissions if `admin_privileges.manage_resoures` is enabled.



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `actions` (Set of String) List of pre-defined actions (READ_REPOSITORY, ANNOTATE_REPOSITORY, DEPLOY_CACHE_REPOSITORY, DELETE_OVERWRITE_REPOSITORY, MANAGE_XRAY_MD_REPOSITORY, READ_RELEASE_BUNDLE, ANNOTATE_RELEASE_BUNDLE, CREATE_RELEASE_BUNDLE, DISTRIBUTE_RELEASE_BUNDLE, DELETE_RELEASE_BUNDLE, MANAGE_XRAY_MD_RELEASE_BUNDLE, READ_BUILD, ANNOTATE_BUILD, DEPLOY_BUILD, DELETE_BUILD, MANAGE_XRAY_MD_BUILD, READ_SOURCES_PIPELINE, TRIGGER_PIPELINE, READ_INTEGRATIONS_PIPELINE, READ_POOLS_PIPELINE, MANAGE_INTEGRATIONS_PIPELINE, MANAGE_SOURCES_PIPELINE, MANAGE_POOLS_PIPELINE, TRIGGER_SECURITY, ISSUES_SECURITY, LICENCES_SECURITY, REPORTS_SECURITY, WATCHES_SECURITY, POLICIES_SECURITY, RULES_SECURITY, MANAGE_MEMBERS, MANAGE_RESOURCES)
- `environments` (Set of String) A repository can be available in different environments. Members with roles defined in the set environment will have access to the repository. List of pre-defined environments (DEV, PROD)
- `name` (String)
- `project_key` (String) Project key for this environment. This field supports only 2 - 20 lowercase alphanumeric and hyphen characters. Must begin with a letter.
- `type` (String) Type of role. Only "CUSTOM" is supported

### Read-Only

- `id` (String) The ID of this resource.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type Membership struct {
func getMembers(d *util.ResourceData, membershipKey string) []Member {
var members []Member

if v, ok := d.GetOkExists(membershipKey); ok {
if v, ok := d.GetOk(membershipKey); ok {
projectMemberships := v.(*schema.Set).List()
if len(projectMemberships) == 0 {
return members
Expand All @@ -58,7 +58,7 @@ func getMembers(d *util.ResourceData, membershipKey string) []Member {
}

var unpackMembers = func(data *schema.ResourceData, membershipKey string) Membership {
d := &util.ResourceData{data}
d := &util.ResourceData{ResourceData: data}
membership := Membership{
Members: getMembers(d, membershipKey),
}
Expand Down Expand Up @@ -95,7 +95,7 @@ var readMembers = func(ctx context.Context, projectKey string, membershipType st
tflog.Debug(ctx, "readMembers")

if membershipType != usersMembershipType && membershipType != groupssMembershipType {
return nil, fmt.Errorf("Invalid membershipType: %s", membershipType)
return nil, fmt.Errorf("invalid membershipType: %s", membershipType)
}

membership := Membership{}
Expand All @@ -121,7 +121,7 @@ var updateMembers = func(ctx context.Context, projectKey string, membershipType
tflog.Trace(ctx, fmt.Sprintf("terraformMembership.Members: %+v\n", terraformMembership.Members))

if membershipType != usersMembershipType && membershipType != groupssMembershipType {
return nil, fmt.Errorf("Invalid membershipType: %s", membershipType)
return nil, fmt.Errorf("invalid membershipType: %s", membershipType)
}

projectMembers, err := readMembers(ctx, projectKey, membershipType, m)
Expand Down Expand Up @@ -159,7 +159,7 @@ var updateMember = func(ctx context.Context, projectKey string, membershipType s
tflog.Trace(ctx, fmt.Sprintf("member: %v", member))

if membershipType != usersMembershipType && membershipType != groupssMembershipType {
return fmt.Errorf("Invalid membershipType: %s", membershipType)
return fmt.Errorf("invalid membershipType: %s", membershipType)
}

_, err := m.(util.ProvderMetadata).Client.R().
Expand Down Expand Up @@ -192,7 +192,7 @@ var deleteMember = func(ctx context.Context, projectKey string, membershipType s
tflog.Trace(ctx, fmt.Sprintf("%+v\n", member))

if membershipType != usersMembershipType && membershipType != groupssMembershipType {
return fmt.Errorf("Invalid membershipType: %s", membershipType)
return fmt.Errorf("invalid membershipType: %s", membershipType)
}

_, err := m.(util.ProvderMetadata).Client.R().
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/jfrog/terraform-provider-shared/test"
)

func TestAccProjectMember(t *testing.T) {
func TestAccProject_membership(t *testing.T) {
name := "tftestprojects" + randSeq(10)
resourceName := "project." + name
projectKey := strings.ToLower(randSeq(6))
Expand All @@ -19,8 +19,8 @@ func TestAccProjectMember(t *testing.T) {
email1 := username1 + "@tempurl.org"
username2 := "user2"
email2 := username2 + "@tempurl.org"
developeRole := "developer"
contributorRole := "contributor"
developeRole := "Developer"
contributorRole := "Contributor"

params := map[string]interface{}{
"name": name,
Expand Down Expand Up @@ -129,9 +129,10 @@ func TestAccProjectMember(t *testing.T) {
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"use_project_role_resource"},
},
{
Config: noMemberConfig,
Expand All @@ -146,15 +147,15 @@ func TestAccProjectMember(t *testing.T) {
})
}

func TestAccProjectGroup(t *testing.T) {
func TestAccProject_group(t *testing.T) {
name := "tftestprojects" + randSeq(10)
resourceName := "project." + name
projectKey := strings.ToLower(randSeq(6))

group1 := "group1"
group2 := "group2"
developeRole := "developer"
contributorRole := "contributor"
developeRole := "Developer"
contributorRole := "Contributor"

params := map[string]interface{}{
"name": name,
Expand Down Expand Up @@ -263,9 +264,10 @@ func TestAccProjectGroup(t *testing.T) {
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"use_project_role_resource"},
},
{
Config: noGroupConfig,
Expand Down
1 change: 1 addition & 0 deletions pkg/project/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func Provider() *schema.Provider {
map[string]*schema.Resource{
"project": projectResource(),
"project_environment": projectEnvironmentResource(),
"project_role": projectRoleResource(),
},
),
}
Expand Down
12 changes: 6 additions & 6 deletions pkg/project/resource_project_repo.go → pkg/project/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,20 @@ import (

type RepoKey string

func (this RepoKey) Id() string {
return string(this)
func (r RepoKey) Id() string {
return string(r)
}

func (this RepoKey) Equals(other Equatable) bool {
return this == other
func (r RepoKey) Equals(other Equatable) bool {
return r == other
}

var unpackRepos = func(data *schema.ResourceData) []RepoKey {
d := &util.ResourceData{data}
d := &util.ResourceData{ResourceData: data}

var repoKeys []RepoKey

if v, ok := d.GetOkExists("repos"); ok {
if v, ok := d.GetOk("repos"); ok {
for _, key := range util.CastToStringArr(v.(*schema.Set).List()) {
repoKeys = append(repoKeys, RepoKey(key))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/jfrog/terraform-provider-shared/test"
)

func TestAccProjectRepo(t *testing.T) {
func TestAccProject_repo(t *testing.T) {
name := "tftestprojects" + randSeq(10)
resourceName := "project." + name
projectKey := strings.ToLower(randSeq(6))
Expand Down Expand Up @@ -105,9 +105,10 @@ func TestAccProjectRepo(t *testing.T) {
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"use_project_role_resource"},
},
{
Config: noReposConfig,
Expand All @@ -125,7 +126,7 @@ func TestAccProjectRepo(t *testing.T) {
/*
Test to assign large number of repositories to a project
*/
func TestAccProjectRepoAssignMultipleRepos(t *testing.T) {
func TestAccProject_repoAssignMultipleRepos(t *testing.T) {

const numRepos = 5
const repoNameInitial = "repo-"
Expand Down Expand Up @@ -229,9 +230,10 @@ func TestAccProjectRepoAssignMultipleRepos(t *testing.T) {
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"use_project_role_resource"},
},
{
Config: noReposConfig,
Expand All @@ -246,7 +248,7 @@ func TestAccProjectRepoAssignMultipleRepos(t *testing.T) {
})
}

func TestAccProjectRepoUnassignNonexistantRepo(t *testing.T) {
func TestAccProject_repoUnassignNonexistantRepo(t *testing.T) {
name := "tftestprojects" + randSeq(10)
resourceName := "project." + name
projectKey := strings.ToLower(randSeq(6))
Expand Down
Loading

0 comments on commit 7043940

Please sign in to comment.