diff --git a/client/api_client.go b/client/api_client.go index e466c5b9..82a40167 100644 --- a/client/api_client.go +++ b/client/api_client.go @@ -31,6 +31,7 @@ type ApiClientInterface interface { ProjectUpdate(id string, payload ProjectUpdatePayload) (Project, error) ProjectDelete(id string) error ProjectMove(id string, targetProjectId string) error + ModuleTestingProject() (*ModuleTestingProject, error) Template(id string) (Template, error) Templates() ([]Template, error) TemplateCreate(payload TemplateCreatePayload) (Template, error) diff --git a/client/api_client_mock.go b/client/api_client_mock.go index 67ad7375..ad358f45 100644 --- a/client/api_client_mock.go +++ b/client/api_client_mock.go @@ -925,6 +925,21 @@ func (mr *MockApiClientInterfaceMockRecorder) ModuleDelete(arg0 any) *gomock.Cal return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModuleDelete", reflect.TypeOf((*MockApiClientInterface)(nil).ModuleDelete), arg0) } +// ModuleTestingProject mocks base method. +func (m *MockApiClientInterface) ModuleTestingProject() (*ModuleTestingProject, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ModuleTestingProject") + ret0, _ := ret[0].(*ModuleTestingProject) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ModuleTestingProject indicates an expected call of ModuleTestingProject. +func (mr *MockApiClientInterfaceMockRecorder) ModuleTestingProject() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModuleTestingProject", reflect.TypeOf((*MockApiClientInterface)(nil).ModuleTestingProject)) +} + // ModuleUpdate mocks base method. func (m *MockApiClientInterface) ModuleUpdate(arg0 string, arg1 ModuleUpdatePayload) (*Module, error) { m.ctrl.T.Helper() diff --git a/client/project.go b/client/project.go index 33347891..e9035720 100644 --- a/client/project.go +++ b/client/project.go @@ -26,6 +26,12 @@ type ProjectUpdatePayload struct { Description string `json:"description"` } +type ModuleTestingProject struct { + Name string `json:"name"` + ParentProjectId string `json:"parentProjectId"` + Id string `json:"id"` +} + func (client *ApiClient) Projects() ([]Project, error) { organizationId, err := client.OrganizationId() if err != nil { @@ -99,3 +105,17 @@ func (client *ApiClient) ProjectMove(id string, targetProjectId string) error { return client.http.Post("/projects/"+id+"/move", payload, nil) } + +func (client *ApiClient) ModuleTestingProject() (*ModuleTestingProject, error) { + organizationId, err := client.OrganizationId() + if err != nil { + return nil, err + } + + var result ModuleTestingProject + if err := client.http.Get("/projects/modules/testing/"+organizationId, nil, &result); err != nil { + return nil, err + } + + return &result, nil +} diff --git a/client/project_test.go b/client/project_test.go index def86b93..7336b133 100644 --- a/client/project_test.go +++ b/client/project_test.go @@ -13,6 +13,7 @@ const parentProjectId = "parent_project_id" var _ = Describe("Project", func() { var project Project + var moduleTestingProject *ModuleTestingProject mockProject := Project{ Id: "idX", Name: "projectX", @@ -20,6 +21,12 @@ var _ = Describe("Project", func() { OrganizationId: organizationId, } + mockModuleTestingProject := ModuleTestingProject{ + Id: "idx", + Name: "namex", + ParentProjectId: "parentProjectIdx", + } + Describe("ProjectCreate", func() { BeforeEach(func() { mockOrganizationIdCall(organizationId) @@ -180,4 +187,25 @@ var _ = Describe("Project", func() { It("Should send POST request with project id and nil target project id", func() {}) }) + + Describe("ModuleTestingProject", func() { + BeforeEach(func() { + mockOrganizationIdCall(organizationId) + + httpCall = mockHttpClient.EXPECT(). + Get("/projects/modules/testing/"+organizationId, nil, gomock.Any()). + Do(func(path string, request interface{}, response *ModuleTestingProject) { + *response = mockModuleTestingProject + }) + moduleTestingProject, _ = apiClient.ModuleTestingProject() + }) + + It("Should send GET request", func() { + httpCall.Times(1) + }) + + It("Should return module testing project", func() { + Expect(mockModuleTestingProject).To(Equal(*moduleTestingProject)) + }) + }) }) diff --git a/env0/data_module_testing_project.go b/env0/data_module_testing_project.go new file mode 100644 index 00000000..b2820d76 --- /dev/null +++ b/env0/data_module_testing_project.go @@ -0,0 +1,49 @@ +package env0 + +import ( + "context" + + "github.com/env0/terraform-provider-env0/client" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataModuleTestingProject() *schema.Resource { + return &schema.Resource{ + ReadContext: dataModuleTestingProjectRead, + Description: "Can be used to get the project_id for agent_project_assignment and cloud_credentials_project_assignment", + + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Description: "the module testing project id", + Computed: true, + }, + "name": { + Type: schema.TypeString, + Description: "the module testing project id", + Computed: true, + }, + "parent_project_id": { + Type: schema.TypeString, + Description: "the module testing parent project id", + Computed: true, + }, + }, + } +} + +func dataModuleTestingProjectRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(client.ApiClientInterface) + + moduleTestingProject, err := client.ModuleTestingProject() + if err != nil { + return diag.Errorf("could not get module testing project: %v", err) + } + + if err := writeResourceData(moduleTestingProject, d); err != nil { + return diag.Errorf("schema resource data serialization failed: %v", err) + } + + return nil +} diff --git a/env0/data_module_testing_project_test.go b/env0/data_module_testing_project_test.go new file mode 100644 index 00000000..8de50114 --- /dev/null +++ b/env0/data_module_testing_project_test.go @@ -0,0 +1,67 @@ +package env0 + +import ( + "errors" + "regexp" + "testing" + + "github.com/env0/terraform-provider-env0/client" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestModuleTestingProjectDataSource(t *testing.T) { + resourceType := "env0_module_testing_project" + resourceName := "test" + accessor := dataSourceAccessor(resourceType, resourceName) + + moduleTestingProject := client.ModuleTestingProject{ + Name: "namex", + ParentProjectId: "pidx", + Id: "idx", + } + + getTestCase := func() resource.TestCase { + return resource.TestCase{ + Steps: []resource.TestStep{ + { + Config: dataSourceConfigCreate(resourceType, resourceName, map[string]interface{}{}), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(accessor, "name", moduleTestingProject.Name), + resource.TestCheckResourceAttr(accessor, "id", moduleTestingProject.Id), + resource.TestCheckResourceAttr(accessor, "parent_project_id", moduleTestingProject.ParentProjectId), + ), + }, + }, + } + } + + mockModuleTestingProject := func() func(mockFunc *client.MockApiClientInterface) { + return func(mock *client.MockApiClientInterface) { + mock.EXPECT().ModuleTestingProject().AnyTimes().Return(&moduleTestingProject, nil) + } + } + + t.Run("Success", func(t *testing.T) { + runUnitTest(t, + getTestCase(), + mockModuleTestingProject(), + ) + }) + + t.Run("API Call Error", func(t *testing.T) { + runUnitTest(t, + resource.TestCase{ + Steps: []resource.TestStep{ + { + Config: dataSourceConfigCreate(resourceType, resourceName, map[string]interface{}{}), + ExpectError: regexp.MustCompile("could not get module testing project: error"), + }, + }, + }, + func(mock *client.MockApiClientInterface) { + mock.EXPECT().ModuleTestingProject().AnyTimes().Return(nil, errors.New("error")) + }, + ) + }) + +} diff --git a/env0/provider.go b/env0/provider.go index 9c7e895a..c192b067 100644 --- a/env0/provider.go +++ b/env0/provider.go @@ -97,6 +97,7 @@ func Provider(version string) plugin.ProviderFunc { "env0_provider": dataProvider(), "env0_custom_flow": dataCustomFlow(), "env0_projects": dataProjects(), + "env0_module_testing_project": dataModuleTestingProject(), }, ResourcesMap: map[string]*schema.Resource{ "env0_project": resourceProject(), diff --git a/examples/data-sources/env0_module_testing_project/data-source.tf b/examples/data-sources/env0_module_testing_project/data-source.tf new file mode 100644 index 00000000..a967a11f --- /dev/null +++ b/examples/data-sources/env0_module_testing_project/data-source.tf @@ -0,0 +1,8 @@ +data "env0_module_testing_project" "project" {} + +data "env0_agents" "agents" {} + +resource "env0_agent_project_assignment" "example" { + agent_id = data.env0_agents.agents.0.agent_key + project_id = env0_module_testing_project.project.id +} diff --git a/tests/integration/002_project/main.tf b/tests/integration/002_project/main.tf index f2c6b09d..7090a2b0 100644 --- a/tests/integration/002_project/main.tf +++ b/tests/integration/002_project/main.tf @@ -66,6 +66,8 @@ data "env0_project" "data_by_name_with_parent_id" { data "env0_projects" "list_of_projects" {} +data "env0_module_testing_project" "module_testing_project" {} + output "test_project_name" { value = replace(env0_project.test_project.name, random_string.random.result, "") }