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

Feat: add parent_project_id as filter for data project resource #762

Merged
merged 2 commits into from
Dec 13, 2023
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
43 changes: 32 additions & 11 deletions env0/data_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,15 @@ func dataProject() *schema.Resource {
},
"parent_project_name": {
Type: schema.TypeString,
Description: "the name of the parent project. Can be used when there are multiple subprojects with the same name under different parent projects",
Description: "the name of the parent project. Can be used as a filter when there are multiple subprojects with the same name under different parent projects",
Optional: true,
},
"parent_project_id": {
Type: schema.TypeString,
Description: "the id of the parent project. Can be used as a filter when there are multiple subprojects with the same name under different parent projects",
Optional: true,
Computed: true,
},
"created_by": {
Type: schema.TypeString,
Description: "textual description of the entity who created the project",
Expand All @@ -49,11 +55,6 @@ func dataProject() *schema.Resource {
Description: "textual description of the project",
Computed: true,
},
"parent_project_id": {
Type: schema.TypeString,
Description: "if the project is a sub-project, returns the parent of this sub-project",
Computed: true,
},
},
}
}
Expand All @@ -73,7 +74,7 @@ func dataProjectRead(ctx context.Context, d *schema.ResourceData, meta interface
if !ok {
return diag.Errorf("either 'name' or 'id' must be specified")
}
project, err = getProjectByName(name.(string), d.Get("parent_project_name").(string), meta)
project, err = getProjectByName(name.(string), d.Get("parent_project_id").(string), d.Get("parent_project_name").(string), meta)
if err != nil {
return diag.Errorf("%v", err)
}
Expand All @@ -86,6 +87,21 @@ func dataProjectRead(ctx context.Context, d *schema.ResourceData, meta interface
return nil
}

func filterByParentProjectId(name string, parentId string, projects []client.Project) ([]client.Project, error) {
filteredProjects := make([]client.Project, 0)
for _, project := range projects {
if len(project.ParentProjectId) == 0 {
continue
}

if project.ParentProjectId == parentId {
filteredProjects = append(filteredProjects, project)
}
}

return filteredProjects, nil
}

func filterByParentProjectName(name string, parentName string, projects []client.Project, meta interface{}) ([]client.Project, error) {
filteredProjects := make([]client.Project, 0)
for _, project := range projects {
Expand All @@ -106,7 +122,7 @@ func filterByParentProjectName(name string, parentName string, projects []client
return filteredProjects, nil
}

func getProjectByName(name string, parentName string, meta interface{}) (client.Project, error) {
func getProjectByName(name string, parentId string, parentName string, meta interface{}) (client.Project, error) {
apiClient := meta.(client.ApiClientInterface)
projects, err := apiClient.Projects()
if err != nil {
Expand All @@ -119,9 +135,14 @@ func getProjectByName(name string, parentName string, meta interface{}) (client.
projectsByName = append(projectsByName, candidate)
}
}

if len(parentName) > 0 {
// Too many results. Use parentName filter to reduce the results.
if len(parentId) > 0 {
// Use parentId filter to reduce the results.
projectsByName, err = filterByParentProjectId(name, parentId, projectsByName)
if err != nil {
return client.Project{}, err
}
} else if len(parentName) > 0 {
// Use parentName filter to reduce the results.
projectsByName, err = filterByParentProjectName(name, parentName, projectsByName, meta)
if err != nil {
return client.Project{}, err
Expand Down
25 changes: 25 additions & 0 deletions env0/data_project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ func TestProjectDataSource(t *testing.T) {
resource.TestCheckResourceAttr(accessor, "role", projectWithParent.Role),
resource.TestCheckResourceAttr(accessor, "description", projectWithParent.Description),
resource.TestCheckResourceAttr(accessor, "parent_project_id", projectWithParent.ParentProjectId),
resource.TestCheckResourceAttr(accessor, "parent_project_name", parentProject.Name),
),
},
},
Expand All @@ -156,6 +157,30 @@ func TestProjectDataSource(t *testing.T) {
)
})

t.Run("By Name with Parent Id", func(t *testing.T) {
runUnitTest(t,
resource.TestCase{
Steps: []resource.TestStep{
{
Config: dataSourceConfigCreate(resourceType, resourceName, map[string]interface{}{"name": projectWithParent.Name, "parent_project_id": parentProject.Id}),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(accessor, "id", projectWithParent.Id),
resource.TestCheckResourceAttr(accessor, "name", projectWithParent.Name),
resource.TestCheckResourceAttr(accessor, "created_by", projectWithParent.CreatedBy),
resource.TestCheckResourceAttr(accessor, "role", projectWithParent.Role),
resource.TestCheckResourceAttr(accessor, "description", projectWithParent.Description),
resource.TestCheckResourceAttr(accessor, "parent_project_id", projectWithParent.ParentProjectId),
resource.TestCheckNoResourceAttr(accessor, "parent_project_name"),
),
},
},
},
func(mock *client.MockApiClientInterface) {
mock.EXPECT().Projects().AnyTimes().Return([]client.Project{projectWithParent, otherProjectWithParent}, nil)
},
)
})

t.Run("Throw error when no name or id is supplied", func(t *testing.T) {
runUnitTest(t,
getErrorTestCase(map[string]interface{}{}, "one of `id,name` must be specified"),
Expand Down
2 changes: 1 addition & 1 deletion env0/resource_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ func resourceProjectImport(ctx context.Context, d *schema.ResourceData, meta int
} else {
tflog.Info(ctx, "Resolving project by name", map[string]interface{}{"name": id})

if project, err = getProjectByName(id, "", meta); err != nil {
if project, err = getProjectByName(id, "", "", meta); err != nil {
return nil, err
}
}
Expand Down
10 changes: 10 additions & 0 deletions examples/data-sources/env0_project/data-source.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
data "env0_project" "default_project" {
name = "Default Organization Project"
}

data "env0_project" "with_parent_name_filter" {
name = "Default Organization Project"
parent_project_name = "parent projet name"
}

data "env0_project" "with_parent_id_filter" {
name = "Default Organization Project"
parent_project_id = "parent-projet-id"
}
5 changes: 5 additions & 0 deletions tests/integration/002_project/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ data "env0_project" "data_by_name_with_parent_name" {
parent_project_name = env0_project.test_project_other.name
}

data "env0_project" "data_by_name_with_parent_id" {
name = env0_project.test_sub_project_other.name
parent_project_id = env0_project.test_project_other.id
}

output "test_project_name" {
value = replace(env0_project.test_project.name, random_string.random.result, "")
}
Expand Down
Loading