diff options
7 files changed, 524 insertions, 0 deletions
diff --git a/azuredevops/internal/acceptancetests/resource_serviceendpoint_externaltfs_test.go b/azuredevops/internal/acceptancetests/resource_serviceendpoint_externaltfs_test.go new file mode 100644 index 00000000..6ee6f16a --- /dev/null +++ b/azuredevops/internal/acceptancetests/resource_serviceendpoint_externaltfs_test.go @@ -0,0 +1,148 @@ +//go:build (all || resource_serviceendpoint_externaltfs) && !exclude_serviceendpoints +// +build all resource_serviceendpoint_externaltfs +// +build !exclude_serviceendpoints + +package acceptancetests + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/microsoft/terraform-provider-azuredevops/azuredevops/internal/acceptancetests/testutils" +) + +func TestAccServiceEndpointExternalTFS_PersonalTokenBasic(t *testing.T) { + projectName := testutils.GenerateResourceName() + serviceEndpointName := testutils.GenerateResourceName() + resourceType := "azuredevops_serviceendpoint_externaltfs" + tfSvcEpNode := resourceType + ".serviceendpoint" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testutils.PreCheck(t, nil) }, + Providers: testutils.GetProviders(), + CheckDestroy: testutils.CheckServiceEndpointDestroyed(resourceType), + Steps: []resource.TestStep{ + { + Config: hclSvcEndpointExternalTFSResourceBasic(projectName, serviceEndpointName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(tfSvcEpNode, "project_id"), + resource.TestCheckResourceAttr(tfSvcEpNode, "auth_personal.#", "1"), + resource.TestCheckResourceAttr(tfSvcEpNode, "service_endpoint_name", serviceEndpointName), + resource.TestCheckResourceAttr(tfSvcEpNode, "description", "Managed by Terraform"), + resource.TestCheckResourceAttr(tfSvcEpNode, "connection_url", "https://dev.azure.com/myorganization"), + testutils.CheckServiceEndpointExistsWithName(tfSvcEpNode, serviceEndpointName), + ), + }, + }, + }) +} + +func TestAccServiceEndpointExternalTFS_PersonalTokenUpdate(t *testing.T) { + projectName := testutils.GenerateResourceName() + serviceEndpointNameFirst := testutils.GenerateResourceName() + serviceEndpointNameSecond := testutils.GenerateResourceName() + description := "Managed by Terraform" + resourceType := "azuredevops_serviceendpoint_externaltfs" + tfSvcEpNode := resourceType + ".serviceendpoint" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testutils.PreCheck(t, nil) }, + Providers: testutils.GetProviders(), + CheckDestroy: testutils.CheckServiceEndpointDestroyed(resourceType), + Steps: []resource.TestStep{ + { + Config: hclSvcEndpointExternalTFSResourceBasic(projectName, serviceEndpointNameFirst), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(tfSvcEpNode, "project_id"), + resource.TestCheckResourceAttr(tfSvcEpNode, "auth_personal.#", "1"), + resource.TestCheckResourceAttr(tfSvcEpNode, "service_endpoint_name", serviceEndpointNameFirst), + resource.TestCheckResourceAttr(tfSvcEpNode, "connection_url", "https://dev.azure.com/myorganization"), + testutils.CheckServiceEndpointExistsWithName(tfSvcEpNode, serviceEndpointNameFirst), + ), + }, + { + Config: hclSvcEndpointExternalTFSResourceUpdate(projectName, serviceEndpointNameSecond, description), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(tfSvcEpNode, "project_id"), + resource.TestCheckResourceAttr(tfSvcEpNode, "auth_personal.#", "1"), + resource.TestCheckResourceAttr(tfSvcEpNode, "service_endpoint_name", serviceEndpointNameSecond), + resource.TestCheckResourceAttr(tfSvcEpNode, "description", description), + resource.TestCheckResourceAttr(tfSvcEpNode, "connection_url", "https://dev.azure.com/myorganization"), + testutils.CheckServiceEndpointExistsWithName(tfSvcEpNode, serviceEndpointNameSecond), + ), + }, + }, + }) +} + +func TestAccServiceEndpointExternalTFS_CreateAndUpdate(t *testing.T) { + projectName := testutils.GenerateResourceName() + serviceEndpointNameFirst := testutils.GenerateResourceName() + serviceEndpointNameSecond := testutils.GenerateResourceName() + resourceType := "azuredevops_serviceendpoint_externaltfs" + tfSvcEpNode := resourceType + ".serviceendpoint" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testutils.PreCheck(t, nil) }, + Providers: testutils.GetProviders(), + CheckDestroy: testutils.CheckServiceEndpointDestroyed(resourceType), + Steps: []resource.TestStep{ + { + Config: hclSvcEndpointExternalTFSResourceBasic(projectName, serviceEndpointNameFirst), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(tfSvcEpNode, "project_id"), + resource.TestCheckResourceAttr(tfSvcEpNode, "auth_personal.#", "1"), + resource.TestCheckResourceAttr(tfSvcEpNode, "service_endpoint_name", serviceEndpointNameFirst), + resource.TestCheckResourceAttr(tfSvcEpNode, "description", "Managed by Terraform"), + resource.TestCheckResourceAttr(tfSvcEpNode, "connection_url", "https://dev.azure.com/myorganization"), + testutils.CheckServiceEndpointExistsWithName(tfSvcEpNode, serviceEndpointNameFirst), + ), + }, + { + Config: hclSvcEndpointExternalTFSResourceBasic(projectName, serviceEndpointNameSecond), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(tfSvcEpNode, "project_id"), + resource.TestCheckResourceAttr(tfSvcEpNode, "auth_personal.#", "1"), + resource.TestCheckResourceAttr(tfSvcEpNode, "service_endpoint_name", serviceEndpointNameSecond), + resource.TestCheckResourceAttr(tfSvcEpNode, "description", "Managed by Terraform"), + resource.TestCheckResourceAttr(tfSvcEpNode, "connection_url", "https://dev.azure.com/myorganization"), + testutils.CheckServiceEndpointExistsWithName(tfSvcEpNode, serviceEndpointNameSecond), + ), + }, + { + ResourceName: tfSvcEpNode, + ImportStateIdFunc: testutils.ComputeProjectQualifiedResourceImportID(tfSvcEpNode), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"auth_personal"}, + }, + }, + }) +} + +func hclSvcEndpointExternalTFSResourceBasic(projectName string, serviceEndpointName string) string { + projectResource := testutils.HclProjectResource(projectName) + serviceEndpointResource := fmt.Sprintf(` +resource "azuredevops_serviceendpoint_externaltfs" "serviceendpoint" { + project_id = azuredevops_project.project.id + service_endpoint_name = "%[1]s" + connection_url = "https://dev.azure.com/myorganization" + auth_personal { + personal_access_token = "test_token_basic" + } +}`, serviceEndpointName) + return fmt.Sprintf("%s\n%s", projectResource, serviceEndpointResource) +} + +func hclSvcEndpointExternalTFSResourceUpdate(projectName string, serviceEndpointName string, description string) string { + projectResource := testutils.HclProjectResource(projectName) + serviceEndpointResource := fmt.Sprintf(` +resource "azuredevops_serviceendpoint_externaltfs" "serviceendpoint" { + project_id = azuredevops_project.project.id + service_endpoint_name = "%[1]s" + connection_url = "https://dev.azure.com/myorganization" + auth_personal { + personal_access_token = "test_token_update" + } + description = "%[2]s" +}`, serviceEndpointName, description) + return fmt.Sprintf("%s\n%s", projectResource, serviceEndpointResource) +} diff --git a/azuredevops/internal/service/serviceendpoint/resource_serviceendpoint_externaltfs.go b/azuredevops/internal/service/serviceendpoint/resource_serviceendpoint_externaltfs.go new file mode 100644 index 00000000..9e97e39c --- /dev/null +++ b/azuredevops/internal/service/serviceendpoint/resource_serviceendpoint_externaltfs.go @@ -0,0 +1,111 @@ +package serviceendpoint + +import ( + "strings" + + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/microsoft/azure-devops-go-api/azuredevops/v6/serviceendpoint" + "github.com/microsoft/terraform-provider-azuredevops/azuredevops/internal/utils/converter" + "github.com/microsoft/terraform-provider-azuredevops/azuredevops/internal/utils/tfhelper" +) + +const ( + personalAccessTokenExternalTFS = "personal_access_token" +) + +func ResourceServiceEndpointExternalTFS() *schema.Resource { + r := genBaseServiceEndpointResource(flattenServiceEndpointExternalTFS, expandServiceEndpointExternalTFS) + r.Schema["connection_url"] = &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.IsURLWithHTTPorHTTPS, + Required: true, + Description: "URL of the Azure DevOps organization or the TFS Project Collection to connect to.", + } + authPersonal := &schema.Resource{ + Schema: map[string]*schema.Schema{ + personalAccessTokenExternalTFS: { + Type: schema.TypeString, + Required: true, + DefaultFunc: schema.EnvDefaultFunc("AZDO_PERSONAL_ACCESS_TOKEN", nil), + Description: "Personal access tokens are applicable only for connections targeting Azure DevOps organization or TFS 2017 (and higher)", + Sensitive: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + } + patHashKey, patHashSchema := tfhelper.GenerateSecreteMemoSchema(personalAccessTokenExternalTFS) + authPersonal.Schema[patHashKey] = patHashSchema + r.Schema["auth_personal"] = &schema.Schema{ + Type: schema.TypeSet, + MinItems: 1, + MaxItems: 1, + Elem: authPersonal, + Required: true, + } + return r +} + +func expandServiceEndpointExternalTFS(d *schema.ResourceData) (*serviceendpoint.ServiceEndpoint, *uuid.UUID, error) { + serviceEndpoint, projectID := doBaseExpansion(d) + serviceEndpoint.Type = converter.String("externaltfs") + serviceEndpoint.Url = converter.String(d.Get("connection_url").(string)) + + scheme := "Token" + parameters := map[string]string{} + + if config, ok := d.GetOk("auth_personal"); ok { + scheme = "Token" + parameters = expandAuthPersonalSetExternalTFS(config.(*schema.Set)) + } + + serviceEndpoint.Authorization = &serviceendpoint.EndpointAuthorization{ + Parameters: ¶meters, + Scheme: &scheme, + } + return serviceEndpoint, projectID, nil +} + +func expandAuthPersonalSetExternalTFS(d *schema.Set) map[string]string { + authPerson := make(map[string]string) + val := d.List()[0].(map[string]interface{}) + + authPerson["apitoken"] = val[personalAccessTokenExternalTFS].(string) + return authPerson +} + +func flattenServiceEndpointExternalTFS( + d *schema.ResourceData, + serviceEndpoint *serviceendpoint.ServiceEndpoint, + projectID *uuid.UUID, +) { + doBaseFlattening(d, serviceEndpoint, projectID) + + if strings.EqualFold(*serviceEndpoint.Authorization.Scheme, "Token") { + authPersonalSet := d.Get("auth_personal").(*schema.Set).List() + authPersonal := flattenAuthPersonExternalTFS(d, authPersonalSet) + if authPersonal != nil { + d.Set("auth_personal", authPersonal) + } + } + + d.Set("connection_url", *serviceEndpoint.Url) +} + +func flattenAuthPersonExternalTFS(d *schema.ResourceData, authPersonalSet []interface{}) []interface{} { + if len(authPersonalSet) == 1 { + if authPersonal, ok := authPersonalSet[0].(map[string]interface{}); ok { + newHash, hashKey := tfhelper.HelpFlattenSecretNested( + d, + "auth_personal", + authPersonal, + personalAccessTokenExternalTFS, + ) + authPersonal[hashKey] = newHash + return []interface{}{authPersonal} + } + } + return nil +} diff --git a/azuredevops/internal/service/serviceendpoint/resource_serviceendpoint_externaltfs_test.go b/azuredevops/internal/service/serviceendpoint/resource_serviceendpoint_externaltfs_test.go new file mode 100644 index 00000000..fc7fc7be --- /dev/null +++ b/azuredevops/internal/service/serviceendpoint/resource_serviceendpoint_externaltfs_test.go @@ -0,0 +1,192 @@ +//go:build (all || resource_serviceendpoint_externaltfs) && !exclude_serviceendpoints +// +build all resource_serviceendpoint_externaltfs +// +build !exclude_serviceendpoints + +package serviceendpoint + +import ( + "context" + "errors" + "testing" + + "github.com/golang/mock/gomock" + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/microsoft/azure-devops-go-api/azuredevops/v6/serviceendpoint" + "github.com/microsoft/terraform-provider-azuredevops/azdosdkmocks" + "github.com/microsoft/terraform-provider-azuredevops/azuredevops/internal/client" + "github.com/microsoft/terraform-provider-azuredevops/azuredevops/internal/utils/converter" + "github.com/stretchr/testify/require" +) + +var ( + externalTfsTestServiceEndpointID = uuid.New() + externalTfsRandomServiceEndpointProjectID = uuid.New() + externalTfsTestServiceEndpointProjectID = &externalTfsRandomServiceEndpointProjectID +) + +var externalTfsTestServiceEndpoint = serviceendpoint.ServiceEndpoint{ + Authorization: &serviceendpoint.EndpointAuthorization{ + Parameters: &map[string]string{ + "apitoken": "UNIT_TEST_ACCESS_TOKEN", + }, + Scheme: converter.String("Token"), + }, + Id: &externalTfsTestServiceEndpointID, + Name: converter.String("UNIT_TEST_NAME"), + Owner: converter.String("library"), + Type: converter.String("externaltfs"), + Url: converter.String("https://dev.azure.com/myorganization"), + ServiceEndpointProjectReferences: &[]serviceendpoint.ServiceEndpointProjectReference{ + { + ProjectReference: &serviceendpoint.ProjectReference{ + Id: externalTfsTestServiceEndpointProjectID, + }, + Name: converter.String("UNIT_TEST_NAME"), + Description: converter.String("UNIT_TEST_DESCRIPTION"), + }, + }, +} + +func TestServiceEndpointExternalTFS_ExpandFlatten_Roundtrip(t *testing.T) { + resourceData := schema.TestResourceDataRaw(t, ResourceServiceEndpointExternalTFS().Schema, nil) + configureExternalTfsAuthPersonal(resourceData) + flattenServiceEndpointExternalTFS( + resourceData, + &externalTfsTestServiceEndpoint, + externalTfsTestServiceEndpointProjectID, + ) + + serviceEndpointAfterRoundTrip, projectID, err := expandServiceEndpointExternalTFS(resourceData) + + require.Nil(t, err) + require.Equal(t, externalTfsTestServiceEndpoint, *serviceEndpointAfterRoundTrip) + require.Equal(t, externalTfsTestServiceEndpointProjectID, projectID) +} + +func TestServiceEndpointExternalTFS_Create_DoesNotSwallowError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + r := ResourceServiceEndpointExternalTFS() + resourceData := schema.TestResourceDataRaw(t, r.Schema, nil) + configureExternalTfsAuthPersonal(resourceData) + flattenServiceEndpointExternalTFS( + resourceData, + &externalTfsTestServiceEndpoint, + externalTfsTestServiceEndpointProjectID, + ) + + buildClient := azdosdkmocks.NewMockServiceendpointClient(ctrl) + clients := &client.AggregatedClient{ServiceEndpointClient: buildClient, Ctx: context.Background()} + + expectedArgs := serviceendpoint.CreateServiceEndpointArgs{Endpoint: &externalTfsTestServiceEndpoint} + buildClient. + EXPECT(). + CreateServiceEndpoint(clients.Ctx, expectedArgs). + Return(nil, errors.New("CreateServiceEndpoint() Failed")). + Times(1) + + err := r.Create(resourceData, clients) + require.Contains(t, err.Error(), "CreateServiceEndpoint() Failed") +} + +func TestServiceEndpointExternalTFS_Read_DoesNotSwallowError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + r := ResourceServiceEndpointExternalTFS() + resourceData := schema.TestResourceDataRaw(t, r.Schema, nil) + flattenServiceEndpointExternalTFS( + resourceData, + &externalTfsTestServiceEndpoint, + externalTfsTestServiceEndpointProjectID, + ) + + buildClient := azdosdkmocks.NewMockServiceendpointClient(ctrl) + clients := &client.AggregatedClient{ServiceEndpointClient: buildClient, Ctx: context.Background()} + + expectedArgs := serviceendpoint.GetServiceEndpointDetailsArgs{ + EndpointId: externalTfsTestServiceEndpoint.Id, + Project: converter.String(externalTfsTestServiceEndpointProjectID.String()), + } + buildClient. + EXPECT(). + GetServiceEndpointDetails(clients.Ctx, expectedArgs). + Return(nil, errors.New("GetServiceEndpoint() Failed")). + Times(1) + + err := r.Read(resourceData, clients) + require.Contains(t, err.Error(), "GetServiceEndpoint() Failed") +} + +func TestServiceEndpointExternalTFS_Delete_DoesNotSwallowError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + r := ResourceServiceEndpointExternalTFS() + resourceData := schema.TestResourceDataRaw(t, r.Schema, nil) + flattenServiceEndpointExternalTFS( + resourceData, + &externalTfsTestServiceEndpoint, + externalTfsTestServiceEndpointProjectID, + ) + + buildClient := azdosdkmocks.NewMockServiceendpointClient(ctrl) + clients := &client.AggregatedClient{ServiceEndpointClient: buildClient, Ctx: context.Background()} + + expectedArgs := serviceendpoint.DeleteServiceEndpointArgs{ + EndpointId: externalTfsTestServiceEndpoint.Id, + ProjectIds: &[]string{ + externalTfsTestServiceEndpointProjectID.String(), + }, + } + + buildClient. + EXPECT(). + DeleteServiceEndpoint(clients.Ctx, expectedArgs). + Return(errors.New("DeleteServiceEndpoint() Failed")). + Times(1) + + err := r.Delete(resourceData, clients) + require.Contains(t, err.Error(), "DeleteServiceEndpoint() Failed") +} + +func TestServiceEndpointExternalTFS_Update_DoesNotSwallowError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + r := ResourceServiceEndpointExternalTFS() + resourceData := schema.TestResourceDataRaw(t, r.Schema, nil) + configureExternalTfsAuthPersonal(resourceData) + flattenServiceEndpointExternalTFS( + resourceData, + &externalTfsTestServiceEndpoint, + externalTfsTestServiceEndpointProjectID, + ) + + buildClient := azdosdkmocks.NewMockServiceendpointClient(ctrl) + clients := &client.AggregatedClient{ServiceEndpointClient: buildClient, Ctx: context.Background()} + + expectedArgs := serviceendpoint.UpdateServiceEndpointArgs{ + Endpoint: &externalTfsTestServiceEndpoint, + EndpointId: externalTfsTestServiceEndpoint.Id, + } + + buildClient. + EXPECT(). + UpdateServiceEndpoint(clients.Ctx, expectedArgs). + Return(nil, errors.New("UpdateServiceEndpoint() Failed")). + Times(1) + + err := r.Update(resourceData, clients) + require.Contains(t, err.Error(), "UpdateServiceEndpoint() Failed") +} + +func configureExternalTfsAuthPersonal(d *schema.ResourceData) { + d.Set("auth_personal", &[]map[string]interface{}{ + { + personalAccessTokenExternalTFS: "UNIT_TEST_ACCESS_TOKEN", + }, + }) +} diff --git a/azuredevops/provider.go b/azuredevops/provider.go index 96229c24..9aa3726b 100644 --- a/azuredevops/provider.go +++ b/azuredevops/provider.go @@ -66,6 +66,7 @@ func Provider() *schema.Provider { "azuredevops_serviceendpoint_npm": serviceendpoint.ResourceServiceEndpointNpm(), "azuredevops_serviceendpoint_generic": serviceendpoint.ResourceServiceEndpointGeneric(), "azuredevops_serviceendpoint_generic_git": serviceendpoint.ResourceServiceEndpointGenericGit(), + "azuredevops_serviceendpoint_externaltfs": serviceendpoint.ResourceServiceEndpointExternalTFS(), "azuredevops_git_repository": git.ResourceGitRepository(), "azuredevops_git_repository_file": git.ResourceGitRepositoryFile(), "azuredevops_user_entitlement": memberentitlementmanagement.ResourceUserEntitlement(), diff --git a/azuredevops/provider_test.go b/azuredevops/provider_test.go index b5c27fb9..92d264c7 100644 --- a/azuredevops/provider_test.go +++ b/azuredevops/provider_test.go @@ -43,6 +43,7 @@ func TestProvider_HasChildResources(t *testing.T) { "azuredevops_serviceendpoint_generic_git", "azuredevops_serviceendpoint_octopusdeploy", "azuredevops_serviceendpoint_incomingwebhook", + "azuredevops_serviceendpoint_externaltfs", "azuredevops_variable_group", "azuredevops_repository_policy_author_email_pattern", "azuredevops_repository_policy_case_enforcement", diff --git a/website/azuredevops.erb b/website/azuredevops.erb index 241da55e..79e516e1 100644 --- a/website/azuredevops.erb +++ b/website/azuredevops.erb @@ -218,6 +218,9 @@ <a href="/docs/providers/azuredevops/r/serviceendpoint_github_enterprise.html">azuredevops_serviceendpoint_github_enterprise</a> </li> <li> + <a href="/docs/providers/azuredevops/r/serviceendpoint_externaltfs.html">azuredevops_serviceendpoint_externaltfs</a> + </li> + <li> <a href="/docs/providers/azuredevops/r/serviceendpoint_incomingwebhook.html">azuredevops_serviceendpoint_incomingwebhook</a> </li> <li> diff --git a/website/docs/r/serviceendpoint_externaltfs.html.markdown b/website/docs/r/serviceendpoint_externaltfs.html.markdown new file mode 100644 index 00000000..45598f91 --- /dev/null +++ b/website/docs/r/serviceendpoint_externaltfs.html.markdown @@ -0,0 +1,68 @@ +--- +layout: "azuredevops" +page_title: "AzureDevops: azuredevops_serviceendpoint_externaltfs" +description: |- + Manages an Azure Repos/Team Foundation Server service endpoint within Azure DevOps organization. +--- + +# azuredevops_serviceendpoint_externaltfs + +Manages an Azure Repos/Team Foundation Server service endpoint within Azure DevOps. + +## Example Usage + +```hcl +resource "azuredevops_project" "example" { + name = "Example Project" + visibility = "private" + version_control = "Git" + work_item_template = "Agile" + description = "Managed by Terraform" +} + +resource "azuredevops_serviceendpoint_externaltfs" "example" { + project_id = azuredevops_project.example.id + service_endpoint_name = "Example External TFS Name" + url = "https://dev.azure.com/myorganization" + description = "Managed by Terraform" + + auth_personal { + # Also can be set with AZDO_PERSONAL_ACCESS_TOKEN environment variable + personal_access_token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +- `project_id` - (Required) The ID of the project. +- `service_endpoint_name` - (Required) The Service Endpoint name. +- `url` - (Required) Azure DevOps Organization or TFS Project Collection Url. +- `description` - (Optional) The Service Endpoint description. Defaults to `Managed by Terraform`. +- `auth_personal` - (Optional) An `auth_personal` block as documented below. Allows connecting using a personal access token. + +`auth_personal` block supports the following: + +- `personal_access_token` - (Required) The Personal Access Token for Azure DevOps Organization. + +## Attributes Reference + +The following attributes are exported: + +- `id` - The ID of the service endpoint. +- `project_id` - The ID of the project. +- `service_endpoint_name` - The Service Endpoint name. + +## Relevant Links + +- [Azure DevOps Service REST API 6.0 - Service Endpoints](https://docs.microsoft.com/en-us/rest/api/azure/devops/serviceendpoint/endpoints?view=azure-devops-rest-6.0) + +## Import + +Azure DevOps Service Endpoint External TFS can be imported using **projectID/serviceEndpointID** or **projectName/serviceEndpointID** + +```sh +terraform import azuredevops_serviceendpoint_externaltfs.example 00000000-0000-0000-0000-000000000000/00000000-0000-0000-0000-000000000000 +``` |
