summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md6
-rw-r--r--azuredevops/data_git_repositories.go218
-rw-r--r--azuredevops/data_git_repositories_test.go299
-rw-r--r--azuredevops/data_projects_test.go37
-rw-r--r--azuredevops/provider.go7
-rw-r--r--azuredevops/provider_test.go3
-rw-r--r--azuredevops/resource_git_repository.go (renamed from azuredevops/resource_azure_git_repository.go)175
-rw-r--r--azuredevops/resource_git_repository_test.go (renamed from azuredevops/resource_azure_git_repository_test.go)82
-rw-r--r--azuredevops/utils/converter/converter.go5
-rw-r--r--azuredevops/utils/testhelper/dataGenerator.go9
-rw-r--r--azuredevops/utils/testhelper/hcl.go2
-rw-r--r--docs/testing.md2
-rw-r--r--examples/azdo-based-cicd/main.tf14
-rw-r--r--website/docs/d/data_git_repositories.html.markdown85
-rw-r--r--website/docs/r/azure_git_repository.html.markdown33
-rw-r--r--website/docs/r/build_definition.html.markdown6
-rw-r--r--website/index.html.markdown1
17 files changed, 837 insertions, 147 deletions
diff --git a/README.md b/README.md
index 10123544..28fc4927 100644
--- a/README.md
+++ b/README.md
@@ -53,7 +53,7 @@ resource "azuredevops_project" "project" {
description = "All of my awesomee things"
}
-resource "azuredevops_azure_git_repository" "repository" {
+resource "azuredevops_git_repository" "repository" {
project_id = azuredevops_project.project.id
name = "My Awesome Repo"
initialization {
@@ -68,8 +68,8 @@ resource "azuredevops_build_definition" "build_definition" {
repository {
repo_type = "TfsGit"
- repo_name = azuredevops_azure_git_repository.repository.name
- branch_name = azuredevops_azure_git_repository.repository.default_branch
+ repo_name = azuredevops_git_repository.repository.name
+ branch_name = azuredevops_git_repository.repository.default_branch
yml_path = "azure-pipelines.yml"
}
}
diff --git a/azuredevops/data_git_repositories.go b/azuredevops/data_git_repositories.go
new file mode 100644
index 00000000..add88c21
--- /dev/null
+++ b/azuredevops/data_git_repositories.go
@@ -0,0 +1,218 @@
+package azuredevops
+
+import (
+ "crypto/sha1"
+ "encoding/base64"
+ "fmt"
+ "log"
+ "strings"
+
+ "github.com/hashicorp/terraform-plugin-sdk/helper/schema"
+ "github.com/hashicorp/terraform/helper/hashcode"
+ "github.com/microsoft/azure-devops-go-api/azuredevops/git"
+ "github.com/microsoft/terraform-provider-azuredevops/azuredevops/utils/config"
+ "github.com/microsoft/terraform-provider-azuredevops/azuredevops/utils/converter"
+ "github.com/microsoft/terraform-provider-azuredevops/azuredevops/utils/suppress"
+ "github.com/microsoft/terraform-provider-azuredevops/azuredevops/utils/validate"
+)
+
+func dataGitRepositories() *schema.Resource {
+ return &schema.Resource{
+ Read: dataSourceGitRepositoriesRead,
+ Schema: map[string]*schema.Schema{
+ "project_id": {
+ Type: schema.TypeString,
+ Optional: true,
+ ValidateFunc: validate.UUID,
+ DiffSuppressFunc: suppress.CaseDifference,
+ },
+ "name": {
+ Type: schema.TypeString,
+ Optional: true,
+ ValidateFunc: validate.NoEmptyStrings,
+ DiffSuppressFunc: suppress.CaseDifference,
+ },
+ "include_hidden": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Default: false,
+ },
+ "repositories": {
+ Type: schema.TypeSet,
+ Computed: true,
+ Set: getGitRepositoryHash,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "name": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "id": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "url": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "ssh_url": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "web_url": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "remote_url": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "project_id": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "size": {
+ Type: schema.TypeInt,
+ Computed: true,
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func getGitRepositoryHash(v interface{}) int {
+ return hashcode.String(v.(map[string]interface{})["id"].(string))
+}
+
+func dataSourceGitRepositoriesRead(d *schema.ResourceData, m interface{}) error {
+ clients := m.(*config.AggregatedClient)
+
+ projectRepos, err := getGitRepositoriesByNameAndProject(d, clients)
+ if err != nil {
+ return fmt.Errorf("Error finding repositories. Error: %v", err)
+ }
+ log.Printf("[TRACE] plugin.terraform-provider-azuredevops: Read [%d] Git repositories", len(*projectRepos))
+
+ results, err := flattenGitRepositories(projectRepos)
+ if err != nil {
+ return fmt.Errorf("Error flattening projects. Error: %v", err)
+ }
+
+ repoNames, err := getAttributeValues(results, "name")
+ if err != nil {
+ return fmt.Errorf("Failed to get list of repository names: %v", err)
+ }
+ id, err := createGitRepositoryDataSourceID(d, &repoNames)
+ if err != nil {
+ return err
+ }
+ d.SetId(id)
+ err = d.Set("repositories", results)
+ if err != nil {
+ d.SetId("")
+ return err
+ }
+ return nil
+}
+
+func createGitRepositoryDataSourceID(d *schema.ResourceData, repoNames *[]string) (string, error) {
+ h := sha1.New()
+ var names []string
+ if nil == repoNames {
+ names = []string{}
+ } else {
+ names = *repoNames
+ }
+ if len(names) <= 0 {
+ names = append(names, "empty")
+ }
+ projectID := d.Get("project_id").(string)
+ if projectID != "" {
+ names = append([]string{projectID}, names...)
+ }
+ if _, err := h.Write([]byte(strings.Join(names, "-"))); err != nil {
+ return "", fmt.Errorf("Unable to compute hash for Git repository names: %v", err)
+ }
+ return "gitRepos#" + base64.URLEncoding.EncodeToString(h.Sum(nil)), nil
+}
+
+func flattenGitRepositories(repos *[]git.GitRepository) ([]interface{}, error) {
+ if repos == nil {
+ return []interface{}{}, nil
+ }
+
+ results := make([]interface{}, 0)
+
+ for _, element := range *repos {
+ output := make(map[string]interface{})
+ if element.Name != nil {
+ output["name"] = *element.Name
+ }
+
+ if element.Id != nil {
+ output["id"] = element.Id.String()
+ }
+
+ if element.Url != nil {
+ output["url"] = *element.Url
+ }
+
+ if element.RemoteUrl != nil {
+ output["remote_url"] = *element.RemoteUrl
+ }
+
+ if element.SshUrl != nil {
+ output["ssh_url"] = *element.SshUrl
+ }
+
+ if element.WebUrl != nil {
+ output["web_url"] = *element.WebUrl
+ }
+
+ if element.Project != nil && element.Project.Id != nil {
+ output["project_id"] = element.Project.Id.String()
+ }
+
+ if element.Size != nil {
+ output["size"] = *element.Size
+ }
+
+ results = append(results, output)
+ }
+
+ return results, nil
+}
+
+func getGitRepositoriesByNameAndProject(d *schema.ResourceData, clients *config.AggregatedClient) (*[]git.GitRepository, error) {
+ var repos *[]git.GitRepository
+ var err error
+ name, projectID := d.Get("name").(string), d.Get("project_id").(string)
+ includeHidden := d.Get("include_hidden").(bool)
+
+ if name != "" && projectID != "" {
+ repo, err := gitRepositoryRead(clients, "", name, projectID)
+ if err != nil {
+ return nil, err
+ }
+ repos = &[]git.GitRepository{*repo}
+ } else {
+ repos, err = clients.GitReposClient.GetRepositories(clients.Ctx, git.GetRepositoriesArgs{
+ Project: converter.String(projectID),
+ IncludeHidden: converter.Bool(includeHidden),
+ })
+ if err != nil {
+ return nil, err
+ }
+ if name != "" {
+ for _, repo := range *repos {
+ if strings.EqualFold(*repo.Name, name) {
+ repos = &[]git.GitRepository{repo}
+ break
+ }
+ }
+ }
+ }
+ return repos, nil
+}
diff --git a/azuredevops/data_git_repositories_test.go b/azuredevops/data_git_repositories_test.go
new file mode 100644
index 00000000..8a8d338f
--- /dev/null
+++ b/azuredevops/data_git_repositories_test.go
@@ -0,0 +1,299 @@
+// +build all core data_git_repositories
+
+package azuredevops
+
+import (
+ "context"
+ "errors"
+ "testing"
+
+ "github.com/golang/mock/gomock"
+ "github.com/hashicorp/terraform-plugin-sdk/helper/schema"
+ "github.com/microsoft/azure-devops-go-api/azuredevops/core"
+ "github.com/microsoft/azure-devops-go-api/azuredevops/git"
+ "github.com/microsoft/terraform-provider-azuredevops/azdosdkmocks"
+ "github.com/microsoft/terraform-provider-azuredevops/azuredevops/utils/config"
+ "github.com/microsoft/terraform-provider-azuredevops/azuredevops/utils/converter"
+ "github.com/microsoft/terraform-provider-azuredevops/azuredevops/utils/testhelper"
+ "github.com/stretchr/testify/require"
+)
+
+func init() {
+ /* add code for test setup here */
+}
+
+var gitRepoListEmpty = []git.GitRepository{}
+
+var azProjectRef = &core.TeamProjectReference{
+ Id: testhelper.CreateUUID(),
+ Name: converter.String("project-01"),
+}
+
+var gitRepoList = []git.GitRepository{
+ {
+ Links: nil,
+ DefaultBranch: nil,
+ Id: testhelper.CreateUUID(),
+ IsFork: converter.Bool(false),
+ Name: converter.String("repo-01"),
+ ParentRepository: nil,
+ Project: azProjectRef,
+ RemoteUrl: nil,
+ Size: nil,
+ SshUrl: nil,
+ Url: nil,
+ ValidRemoteUrls: nil,
+ WebUrl: nil,
+ },
+ {
+ Links: nil,
+ DefaultBranch: converter.String("master"),
+ Id: testhelper.CreateUUID(),
+ IsFork: converter.Bool(true),
+ Name: converter.String("repo-02"),
+ ParentRepository: &git.GitRepositoryRef{
+ Id: testhelper.CreateUUID(),
+ Name: converter.String("repo-parent-02"),
+ },
+ Project: azProjectRef,
+ RemoteUrl: nil,
+ Size: converter.UInt64(0),
+ SshUrl: nil,
+ Url: nil,
+ ValidRemoteUrls: nil,
+ WebUrl: nil,
+ },
+ {
+ Links: nil,
+ DefaultBranch: converter.String("dev"),
+ Id: testhelper.CreateUUID(),
+ IsFork: nil,
+ Name: converter.String("repo-03"),
+ ParentRepository: nil,
+ Project: &core.TeamProjectReference{
+ Id: testhelper.CreateUUID(),
+ Name: converter.String("project-02"),
+ },
+ RemoteUrl: nil,
+ Size: converter.UInt64(1234),
+ SshUrl: nil,
+ Url: nil,
+ ValidRemoteUrls: nil,
+ WebUrl: nil,
+ },
+}
+
+func TestGitRepositoriesDataSource_Read_TestHandleError(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ graphClient := azdosdkmocks.NewMockGraphClient(ctrl)
+ repoClient := azdosdkmocks.NewMockGitClient(ctrl)
+
+ clients := &config.AggregatedClient{
+ GitReposClient: repoClient,
+ GraphClient: graphClient,
+ Ctx: context.Background(),
+ }
+
+ expectedGetRepositoriesArgs := git.GetRepositoriesArgs{
+ IncludeHidden: converter.Bool(false),
+ }
+
+ repoClient.
+ EXPECT().
+ GetRepositories(clients.Ctx, expectedGetRepositoriesArgs).
+ Return(nil, errors.New("GetRepositories() Failed")).
+ Times(1)
+
+ resourceData := schema.TestResourceDataRaw(t, dataGitRepositories().Schema, nil)
+
+ err := dataSourceGitRepositoriesRead(resourceData, clients)
+ require.NotNil(t, err)
+ require.Zero(t, resourceData.Id())
+ repos := resourceData.Get("repositories").(*schema.Set)
+ require.NotNil(t, repos)
+ require.Zero(t, repos.Len())
+}
+
+func TestGitRepositoriesDataSource_Read_TestHandleErrorWithSpecificRepository(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ graphClient := azdosdkmocks.NewMockGraphClient(ctrl)
+ repoClient := azdosdkmocks.NewMockGitClient(ctrl)
+
+ clients := &config.AggregatedClient{
+ GitReposClient: repoClient,
+ GraphClient: graphClient,
+ Ctx: context.Background(),
+ }
+
+ repo := gitRepoList[2]
+ expectedGetRepositoryArgs := git.GetRepositoryArgs{
+ RepositoryId: repo.Name,
+ Project: converter.String(repo.Project.Id.String()),
+ }
+ repoClient.
+ EXPECT().
+ GetRepository(clients.Ctx, expectedGetRepositoryArgs).
+ Return(nil, errors.New("GetRepository() Failed"))
+
+ resourceData := schema.TestResourceDataRaw(t, dataGitRepositories().Schema, nil)
+ resourceData.Set("name", *repo.Name)
+ resourceData.Set("project_id", repo.Project.Id.String())
+
+ err := dataSourceGitRepositoriesRead(resourceData, clients)
+ require.NotNil(t, err)
+ require.Zero(t, resourceData.Id())
+ repos := resourceData.Get("repositories").(*schema.Set)
+ require.NotNil(t, repos)
+ require.Zero(t, repos.Len())
+}
+
+func TestGitRepositoriesDataSource_Read_NoRepositories(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ graphClient := azdosdkmocks.NewMockGraphClient(ctrl)
+ repoClient := azdosdkmocks.NewMockGitClient(ctrl)
+
+ clients := &config.AggregatedClient{
+ GitReposClient: repoClient,
+ GraphClient: graphClient,
+ Ctx: context.Background(),
+ }
+
+ expectedGetRepositoriesArgs := git.GetRepositoriesArgs{
+ IncludeHidden: converter.Bool(false),
+ }
+
+ repoClient.
+ EXPECT().
+ GetRepositories(clients.Ctx, expectedGetRepositoriesArgs).
+ Return(&[]git.GitRepository{}, nil).
+ Times(1)
+
+ resourceData := schema.TestResourceDataRaw(t, dataGitRepositories().Schema, nil)
+
+ err := dataSourceGitRepositoriesRead(resourceData, clients)
+ require.Nil(t, err)
+ repos := resourceData.Get("repositories").(*schema.Set)
+ require.NotNil(t, repos)
+ require.Zero(t, repos.Len())
+}
+
+func TestGitRepositoriesDataSource_Read_AllRepositories(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ graphClient := azdosdkmocks.NewMockGraphClient(ctrl)
+ repoClient := azdosdkmocks.NewMockGitClient(ctrl)
+
+ clients := &config.AggregatedClient{
+ GitReposClient: repoClient,
+ GraphClient: graphClient,
+ Ctx: context.Background(),
+ }
+
+ expectedGetRepositoriesArgs := git.GetRepositoriesArgs{
+ IncludeHidden: converter.Bool(false),
+ }
+
+ repoClient.
+ EXPECT().
+ GetRepositories(clients.Ctx, expectedGetRepositoriesArgs).
+ Return(&gitRepoList, nil).
+ Times(1)
+
+ resourceData := schema.TestResourceDataRaw(t, dataGitRepositories().Schema, nil)
+
+ err := dataSourceGitRepositoriesRead(resourceData, clients)
+ require.Nil(t, err)
+ repos := resourceData.Get("repositories").(*schema.Set)
+ require.NotNil(t, repos)
+ require.Equal(t, repos.Len(), 3)
+}
+
+func TestGitRepositoriesDataSource_Read_AllRepositoriesByProject(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ graphClient := azdosdkmocks.NewMockGraphClient(ctrl)
+ repoClient := azdosdkmocks.NewMockGitClient(ctrl)
+
+ clients := &config.AggregatedClient{
+ GitReposClient: repoClient,
+ GraphClient: graphClient,
+ Ctx: context.Background(),
+ }
+
+ expectedGetRepositoriesArgs := git.GetRepositoriesArgs{
+ Project: converter.String(azProjectRef.Id.String()),
+ IncludeHidden: converter.Bool(false),
+ }
+
+ repoClient.
+ EXPECT().
+ GetRepositories(clients.Ctx, expectedGetRepositoriesArgs).
+ Return(&[]git.GitRepository{
+ gitRepoList[0],
+ gitRepoList[1],
+ }, nil).
+ Times(1)
+
+ resourceData := schema.TestResourceDataRaw(t, dataGitRepositories().Schema, nil)
+ resourceData.Set("project_id", azProjectRef.Id.String())
+
+ err := dataSourceGitRepositoriesRead(resourceData, clients)
+ require.Nil(t, err)
+ repos := resourceData.Get("repositories").(*schema.Set)
+ require.NotNil(t, repos)
+ require.Equal(t, repos.Len(), 2)
+ repoMap := make(map[string]interface{})
+ for _, item := range repos.List() {
+ repoData := item.(map[string]interface{})
+ repoMap[repoData["name"].(string)] = repoData
+ }
+
+ for i := 0; i < 2; i++ {
+ require.Contains(t, repoMap, *gitRepoList[i].Name)
+ repo := repoMap[*gitRepoList[i].Name].(map[string]interface{})
+ require.Equal(t, gitRepoList[i].Project.Id.String(), repo["project_id"])
+ require.Equal(t, gitRepoList[i].Id.String(), repo["id"])
+ }
+}
+
+func TestGitRepositoriesDataSource_Read_SingleRepository(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ graphClient := azdosdkmocks.NewMockGraphClient(ctrl)
+ repoClient := azdosdkmocks.NewMockGitClient(ctrl)
+
+ clients := &config.AggregatedClient{
+ GitReposClient: repoClient,
+ GraphClient: graphClient,
+ Ctx: context.Background(),
+ }
+
+ repo := gitRepoList[1]
+ expectedGetRepositoryArgs := git.GetRepositoryArgs{
+ RepositoryId: repo.Name,
+ Project: converter.String(repo.Project.Id.String()),
+ }
+ repoClient.
+ EXPECT().
+ GetRepository(clients.Ctx, expectedGetRepositoryArgs).
+ Return(&repo, nil)
+
+ resourceData := schema.TestResourceDataRaw(t, dataGitRepositories().Schema, nil)
+ resourceData.Set("name", *repo.Name)
+ resourceData.Set("project_id", repo.Project.Id.String())
+
+ err := dataSourceGitRepositoriesRead(resourceData, clients)
+ require.Nil(t, err)
+ repos := resourceData.Get("repositories").(*schema.Set)
+ require.NotNil(t, repos)
+ require.Equal(t, repos.Len(), 1)
+}
diff --git a/azuredevops/data_projects_test.go b/azuredevops/data_projects_test.go
index 73f21068..f0f0c50f 100644
--- a/azuredevops/data_projects_test.go
+++ b/azuredevops/data_projects_test.go
@@ -16,6 +16,7 @@ import (
"github.com/microsoft/terraform-provider-azuredevops/azdosdkmocks"
"github.com/microsoft/terraform-provider-azuredevops/azuredevops/utils/config"
"github.com/microsoft/terraform-provider-azuredevops/azuredevops/utils/converter"
+ "github.com/microsoft/terraform-provider-azuredevops/azuredevops/utils/testhelper"
"github.com/stretchr/testify/require"
"github.com/golang/mock/gomock"
@@ -25,33 +26,24 @@ func init() {
/* add code for test setup here */
}
-var idList = []uuid.UUID{
- uuid.New(),
- uuid.New(),
- uuid.New(),
- uuid.New(),
- uuid.New(),
- uuid.New(),
-}
-
var prjListEmpty = []core.TeamProjectReference{}
var prjListStateMixed = []core.TeamProjectReference{
{
Name: converter.String("vsteam-0177"),
- Id: &idList[0],
+ Id: testhelper.CreateUUID(),
State: &core.ProjectStateValues.WellFormed,
Url: nil,
},
{
Name: converter.String("vsteam-0178"),
- Id: &idList[1],
+ Id: testhelper.CreateUUID(),
State: &core.ProjectStateValues.Deleted,
Url: nil,
},
{
Name: converter.String("vsteam-0179"),
- Id: &idList[2],
+ Id: testhelper.CreateUUID(),
State: &core.ProjectStateValues.New,
Url: nil,
},
@@ -60,19 +52,19 @@ var prjListStateMixed = []core.TeamProjectReference{
var prjListStateWellFormed = []core.TeamProjectReference{
{
Name: converter.String("vsteam-0177"),
- Id: &idList[0],
+ Id: testhelper.CreateUUID(),
State: &core.ProjectStateValues.WellFormed,
Url: nil,
},
{
Name: converter.String("vsteam-0178"),
- Id: &idList[1],
+ Id: testhelper.CreateUUID(),
State: &core.ProjectStateValues.WellFormed,
Url: nil,
},
{
Name: converter.String("vsteam-0179"),
- Id: &idList[2],
+ Id: testhelper.CreateUUID(),
State: &core.ProjectStateValues.WellFormed,
Url: nil,
},
@@ -81,40 +73,41 @@ var prjListStateWellFormed = []core.TeamProjectReference{
var prjListStateWellFormed2 = []core.TeamProjectReference{
{
Name: converter.String("vsteam-0277"),
- Id: &idList[0+len(prjListStateWellFormed)],
+ Id: testhelper.CreateUUID(),
State: &core.ProjectStateValues.WellFormed,
Url: nil,
},
{
Name: converter.String("vsteam-0278"),
- Id: &idList[1+len(prjListStateWellFormed)],
+ Id: testhelper.CreateUUID(),
State: &core.ProjectStateValues.WellFormed,
Url: nil,
},
{
Name: converter.String("vsteam-0279"),
- Id: &idList[2+len(prjListStateWellFormed)],
+ Id: testhelper.CreateUUID(),
State: &core.ProjectStateValues.WellFormed,
Url: nil,
},
}
+var duplicatePrjID *uuid.UUID = testhelper.CreateUUID()
var prjListDoubleID = []core.TeamProjectReference{
{
Name: converter.String("vsteam-0177"),
- Id: &idList[0],
+ Id: duplicatePrjID,
State: &core.ProjectStateValues.WellFormed,
Url: nil,
},
{
Name: converter.String("vsteam-0178"),
- Id: &idList[1],
+ Id: testhelper.CreateUUID(),
State: &core.ProjectStateValues.WellFormed,
Url: nil,
},
{
Name: converter.String("vsteam-0179"),
- Id: &idList[0],
+ Id: duplicatePrjID,
State: &core.ProjectStateValues.WellFormed,
Url: nil,
},
@@ -160,7 +153,7 @@ func TestDataSourceProjects_Read_TestFindProjectByName(t *testing.T) {
projectReference := projectSet.List()[0].(map[string]interface{})
require.NotNil(t, projectReference)
require.Equal(t, "vsteam-0178", projectReference["name"])
- require.Equal(t, idList[1].String(), projectReference["project_id"])
+ require.Equal(t, prjListStateWellFormed[1].Id.String(), projectReference["project_id"])
require.Equal(t, "wellFormed", projectReference["state"])
}
diff --git a/azuredevops/provider.go b/azuredevops/provider.go
index 60aaa999..d702e036 100644
--- a/azuredevops/provider.go
+++ b/azuredevops/provider.go
@@ -15,15 +15,16 @@ func Provider() *schema.Provider {
"azuredevops_serviceendpoint_github": resourceServiceEndpointGitHub(),
"azuredevops_serviceendpoint_dockerhub": resourceServiceEndpointDockerHub(),
"azuredevops_serviceendpoint_azurerm": resourceServiceEndpointAzureRM(),
- "azuredevops_azure_git_repository": resourceAzureGitRepository(),
+ "azuredevops_git_repository": resourceGitRepository(),
"azuredevops_user_entitlement": resourceUserEntitlement(),
"azuredevops_group_membership": resourceGroupMembership(),
"azuredevops_agent_pool": resourceAzureAgentPool(),
"azuredevops_group": resourceGroup(),
},
DataSourcesMap: map[string]*schema.Resource{
- "azuredevops_group": dataGroup(),
- "azuredevops_projects": dataProjects(),
+ "azuredevops_group": dataGroup(),
+ "azuredevops_projects": dataProjects(),
+ "azuredevops_git_repositories": dataGitRepositories(),
},
Schema: map[string]*schema.Schema{
"org_service_url": {
diff --git a/azuredevops/provider_test.go b/azuredevops/provider_test.go
index e47d7a51..dcb2b657 100644
--- a/azuredevops/provider_test.go
+++ b/azuredevops/provider_test.go
@@ -22,7 +22,7 @@ func TestAzureDevOpsProvider_HasChildResources(t *testing.T) {
"azuredevops_serviceendpoint_dockerhub",
"azuredevops_serviceendpoint_azurerm",
"azuredevops_variable_group",
- "azuredevops_azure_git_repository",
+ "azuredevops_git_repository",
"azuredevops_user_entitlement",
"azuredevops_group_membership",
"azuredevops_group",
@@ -42,6 +42,7 @@ func TestAzureDevOpsProvider_HasChildDataSources(t *testing.T) {
expectedDataSources := []string{
"azuredevops_group",
"azuredevops_projects",
+ "azuredevops_git_repositories",
}
dataSources := provider.DataSourcesMap
diff --git a/azuredevops/resource_azure_git_repository.go b/azuredevops/resource_git_repository.go
index c191695d..8453d9b9 100644
--- a/azuredevops/resource_azure_git_repository.go
+++ b/azuredevops/resource_git_repository.go
@@ -2,6 +2,8 @@ package azuredevops
import (
"fmt"
+ "log"
+
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
@@ -9,28 +11,43 @@ import (
"github.com/microsoft/azure-devops-go-api/azuredevops/git"
"github.com/microsoft/terraform-provider-azuredevops/azuredevops/utils/config"
"github.com/microsoft/terraform-provider-azuredevops/azuredevops/utils/converter"
+ "github.com/microsoft/terraform-provider-azuredevops/azuredevops/utils/suppress"
+ "github.com/microsoft/terraform-provider-azuredevops/azuredevops/utils/validate"
)
-func resourceAzureGitRepository() *schema.Resource {
+func resourceGitRepository() *schema.Resource {
return &schema.Resource{
- Create: resourceAzureGitRepositoryCreate,
- Read: resourceAzureGitRepositoryRead,
- Update: resourceAzureGitRepositoryUpdate,
- Delete: resourceAzureGitRepositoryDelete,
+ Create: resourceGitRepositoryCreate,
+ Read: resourceGitRepositoryRead,
+ Update: resourceGitRepositoryUpdate,
+ Delete: resourceGitRepositoryDelete,
Schema: map[string]*schema.Schema{
"project_id": {
- Type: schema.TypeString,
- Required: true,
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true, // repositories cannot be moved
+ ValidateFunc: validation.NoZeroValues,
+ DiffSuppressFunc: suppress.CaseDifference,
},
"name": {
- Type: schema.TypeString,
- ForceNew: false,
- Required: true,
+ Type: schema.TypeString,
+ ForceNew: false,
+ Required: true,
+ ValidateFunc: validation.NoZeroValues,
+ DiffSuppressFunc: suppress.CaseDifference,
+ },
+ "parent_repository_id": {
+ Type: schema.TypeString,
+ Optional: true,
+ ValidateFunc: validate.UUID,
+ DiffSuppressFunc: suppress.CaseDifference,
},
"default_branch": {
- Type: schema.TypeString,
- Computed: true,
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ ValidateFunc: validation.NoZeroValues,
},
"is_fork": {
Type: schema.TypeBool,
@@ -58,15 +75,14 @@ func resourceAzureGitRepository() *schema.Resource {
},
"initialization": {
Type: schema.TypeSet,
- Required: true,
- MinItems: 1,
+ Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"init_type": {
Type: schema.TypeString,
Required: true,
- ValidateFunc: validation.StringInSlice([]string{"Uninitialized", "Clean", "Fork", "Import"}, false),
+ ValidateFunc: validation.StringInSlice([]string{"uninitialized", "clean", "import"}, true),
},
"source_type": {
Type: schema.TypeString,
@@ -92,45 +108,64 @@ type repoInitializationMeta struct {
sourceURL string
}
-func resourceAzureGitRepositoryCreate(d *schema.ResourceData, m interface{}) error {
+func resourceGitRepositoryCreate(d *schema.ResourceData, m interface{}) error {
clients := m.(*config.AggregatedClient)
- repo, initialization, projectID, err := expandAzureGitRepository(d)
+ repo, initialization, projectID, err := expandGitRepository(d)
if err != nil {
return fmt.Errorf("Error expanding repository resource data: %+v", err)
}
- createdRepo, err := createAzureGitRepository(clients, repo.Name, projectID)
+ var parentRepoRef *git.GitRepositoryRef = nil
+ if parentRepoID, ok := d.GetOkExists("parent_repository_id"); ok {
+ parentRepo, err := gitRepositoryRead(clients, parentRepoID.(string), "", "")
+ if err != nil {
+ return fmt.Errorf("Failed to locate parent repository [%s]: %+v", parentRepoID, err)
+ }
+ parentRepoRef = &git.GitRepositoryRef{
+ Id: parentRepo.Id,
+ Name: parentRepo.Name,
+ Project: parentRepo.Project,
+ }
+ }
+
+ createdRepo, err := createGitRepository(clients, repo.Name, projectID, parentRepoRef)
if err != nil {
return fmt.Errorf("Error creating repository in Azure DevOps: %+v", err)
}
- if initialization.initType == "Clean" {
- err = initializeAzureGitRepository(clients, createdRepo)
+ if initialization != nil && initialization.initType == "Clean" {
+ err = initializeGitRepository(clients, createdRepo)
if err != nil {
+ if err := deleteGitRepository(clients, createdRepo.Id.String()); err != nil {
+ log.Printf("[WARN] Unable to delete new Git Repository after initialization failed: %+v", err)
+ }
return fmt.Errorf("Error initializing repository in Azure DevOps: %+v", err)
}
}
- flattenAzureGitRepository(d, createdRepo)
-
- return resourceAzureGitRepositoryRead(d, m)
+ d.SetId(createdRepo.Id.String())
+ return resourceGitRepositoryRead(d, m)
}
-func createAzureGitRepository(clients *config.AggregatedClient, repoName *string, projectID *uuid.UUID) (*git.GitRepository, error) {
+func createGitRepository(clients *config.AggregatedClient, repoName *string, projectID *uuid.UUID, parentRepo *git.GitRepositoryRef) (*git.GitRepository, error) {
args := git.CreateRepositoryArgs{
GitRepositoryToCreate: &git.GitRepositoryCreateOptions{
Name: repoName,
Project: &core.TeamProjectReference{
Id: projectID,
},
+ ParentRepository: parentRepo,
},
}
createdRepository, err := clients.GitReposClient.CreateRepository(clients.Ctx, args)
+ if err != nil {
+ return nil, err
+ }
- return createdRepository, err
+ return createdRepository, nil
}
-func initializeAzureGitRepository(clients *config.AggregatedClient, repo *git.GitRepository) error {
+func initializeGitRepository(clients *config.AggregatedClient, repo *git.GitRepository) error {
args := git.CreatePushArgs{
RepositoryId: repo.Name,
Project: repo.Project.Name,
@@ -166,38 +201,40 @@ func initializeAzureGitRepository(clients *config.AggregatedClient, repo *git.Gi
return err
}
-func resourceAzureGitRepositoryRead(d *schema.ResourceData, m interface{}) error {
+func resourceGitRepositoryRead(d *schema.ResourceData, m interface{}) error {
repoID := d.Id()
repoName := d.Get("name").(string)
projectID := d.Get("project_id").(string)
clients := m.(*config.AggregatedClient)
- repo, err := azureGitRepositoryRead(clients, repoID, repoName, projectID)
+ repo, err := gitRepositoryRead(clients, repoID, repoName, projectID)
if err != nil {
return fmt.Errorf("Error looking up repository with ID %s and Name %s. Error: %v", repoID, repoName, err)
}
- flattenAzureGitRepository(d, repo)
+ flattenGitRepository(d, repo)
return nil
}
-func resourceAzureGitRepositoryUpdate(d *schema.ResourceData, m interface{}) error {
+func resourceGitRepositoryUpdate(d *schema.ResourceData, m interface{}) error {
clients := m.(*config.AggregatedClient)
- repo, _, projectID, err := expandAzureGitRepository(d)
+ repo, _, projectID, err := expandGitRepository(d)
if err != nil {
return fmt.Errorf("Error converting terraform data model to AzDO project reference: %+v", err)
}
- repo, err = updateAzureGitRepository(clients, repo, projectID)
+ repo, err = updateGitRepository(clients, repo, projectID)
if err != nil {
return fmt.Errorf("Error updating repository in Azure DevOps: %+v", err)
}
- flattenAzureGitRepository(d, repo)
- return resourceAzureGitRepositoryRead(d, m)
+ return resourceGitRepositoryRead(d, m)
}
-func updateAzureGitRepository(clients *config.AggregatedClient, repository *git.GitRepository, project *uuid.UUID) (*git.GitRepository, error) {
+func updateGitRepository(clients *config.AggregatedClient, repository *git.GitRepository, project *uuid.UUID) (*git.GitRepository, error) {
+ if nil == project {
+ return nil, fmt.Errorf("updateGitRepository: ID of project cannot be nil")
+ }
projectID := project.String()
return clients.GitReposClient.UpdateRepository(
clients.Ctx,
@@ -208,13 +245,18 @@ func updateAzureGitRepository(clients *config.AggregatedClient, repository *git.
})
}
-func resourceAzureGitRepositoryDelete(d *schema.ResourceData, m interface{}) error {
+func resourceGitRepositoryDelete(d *schema.ResourceData, m interface{}) error {
repoID := d.Id()
clients := m.(*config.AggregatedClient)
- return deleteAzureGitRepository(clients, repoID)
+ err := deleteGitRepository(clients, repoID)
+ if err != nil {
+ return err
+ }
+ d.SetId("")
+ return nil
}
-func deleteAzureGitRepository(clients *config.AggregatedClient, repoID string) error {
+func deleteGitRepository(clients *config.AggregatedClient, repoID string) error {
uuid, err := uuid.Parse(repoID)
if err != nil {
return fmt.Errorf("Invalid repositoryId UUID: %s", repoID)
@@ -226,7 +268,7 @@ func deleteAzureGitRepository(clients *config.AggregatedClient, repoID string) e
}
// Lookup an Azure Git Repository using the ID, or name if the ID is not set.
-func azureGitRepositoryRead(clients *config.AggregatedClient, repoID string, repoName string, projectID string) (*git.GitRepository, error) {
+func gitRepositoryRead(clients *config.AggregatedClient, repoID string, repoName string, projectID string) (*git.GitRepository, error) {
identifier := repoID
if identifier == "" {
identifier = repoName
@@ -238,9 +280,7 @@ func azureGitRepositoryRead(clients *config.AggregatedClient, repoID string, rep
})
}
-func flattenAzureGitRepository(d *schema.ResourceData, repository *git.GitRepository) {
- d.SetId(repository.Id.String())
-
+func flattenGitRepository(d *schema.ResourceData, repository *git.GitRepository) {
d.Set("name", converter.ToString(repository.Name, ""))
d.Set("project_id", repository.Project.Id.String())
d.Set("default_branch", converter.ToString(repository.DefaultBranch, ""))
@@ -254,12 +294,17 @@ func flattenAzureGitRepository(d *schema.ResourceData, repository *git.GitReposi
// Convert internal Terraform data structure to an AzDO data structure. Note: only the params that are
// not generated by the service are expanded here
-func expandAzureGitRepository(d *schema.ResourceData) (*git.GitRepository, *repoInitializationMeta, *uuid.UUID, error) {
+func expandGitRepository(d *schema.ResourceData) (*git.GitRepository, *repoInitializationMeta, *uuid.UUID, error) {
// an "error" is OK here as it is expected in the case that the ID is not set in the resource data
var repoID *uuid.UUID
- parsedID, err := uuid.Parse(d.Id())
- if err == nil {
- repoID = &parsedID
+ id := d.Id()
+ if id == "" {
+ log.Print("[DEBUG] expandGitRepository: ID is empty (not set)")
+ } else {
+ parsedID, err := uuid.Parse(id)
+ if err == nil {
+ repoID = &parsedID
+ }
}
projectID, err := uuid.Parse(d.Get("project_id").(string))
@@ -268,32 +313,34 @@ func expandAzureGitRepository(d *schema.ResourceData) (*git.GitRepository, *repo
}
repo := &git.GitRepository{
- Id: repoID,
- Name: converter.String(d.Get("name").(string)),
+ Id: repoID,
+ Name: converter.String(d.Get("name").(string)),
+ DefaultBranch: converter.String(d.Get("default_branch").(string)),
}
+ var initialization *repoInitializationMeta = nil
initData := d.Get("initialization").(*schema.Set).List()
// Note: If configured, this will be of length 1 based on the schema definition above.
- if len(initData) != 1 {
- return nil, nil, nil, fmt.Errorf("Unexpectedly did not find repository initialization metadata in the resource data")
- }
+ if len(initData) == 1 {
+ initValues := initData[0].(map[string]interface{})
- initValues := initData[0].(map[string]interface{})
-
- initialization := &repoInitializationMeta{
- initType: initValues["init_type"].(string),
- sourceType: initValues["source_type"].(string),
- sourceURL: initValues["source_url"].(string),
- }
+ initialization = &repoInitializationMeta{
+ initType: initValues["init_type"].(string),
+ sourceType: initValues["source_type"].(string),
+ sourceURL: initValues["source_url"].(string),
+ }
- if initialization.initType == "Fork" || initialization.initType == "Import" {
- return nil, nil, nil, fmt.Errorf("Initialization strategy not implemented: %s", initialization.initType)
- }
+ if initialization.initType == "Import" {
+ return nil, nil, nil, fmt.Errorf("Initialization strategy not implemented: %s", initialization.initType)
+ }
- if initialization.initType == "Clean" {
- initialization.sourceType = ""
- initialization.sourceURL = ""
+ if initialization.initType == "Clean" {
+ initialization.sourceType = ""
+ initialization.sourceURL = ""
+ }
+ } else if len(initData) > 1 {
+ return nil, nil, nil, fmt.Errorf("Multiple initialization blocks")
}
return repo, initialization, &projectID, nil
diff --git a/azuredevops/resource_azure_git_repository_test.go b/azuredevops/resource_git_repository_test.go
index 8a116f77..4c50af2f 100644
--- a/azuredevops/resource_azure_git_repository_test.go
+++ b/azuredevops/resource_git_repository_test.go
@@ -50,8 +50,9 @@ func TestAzureGitRepo_Create_DoesNotSwallowErrorFromFailedCreateCall(t *testing.
ctrl := gomock.NewController(t)
defer ctrl.Finish()
- resourceData := schema.TestResourceDataRaw(t, resourceAzureGitRepository().Schema, nil)
- flattenAzureGitRepository(resourceData, &testAzureGitRepository)
+ resourceData := schema.TestResourceDataRaw(t, resourceGitRepository().Schema, nil)
+ resourceData.SetId(testAzureGitRepository.Id.String())
+ flattenGitRepository(resourceData, &testAzureGitRepository)
configureCleanInitialization(resourceData)
reposClient := azdosdkmocks.NewMockGitClient(ctrl)
@@ -71,7 +72,7 @@ func TestAzureGitRepo_Create_DoesNotSwallowErrorFromFailedCreateCall(t *testing.
Return(nil, errors.New("CreateAzureGitRepository() Failed")).
Times(1)
- err := resourceAzureGitRepositoryCreate(resourceData, clients)
+ err := resourceGitRepositoryCreate(resourceData, clients)
require.Regexp(t, ".*CreateAzureGitRepository\\(\\) Failed$", err.Error())
}
@@ -81,8 +82,9 @@ func TestAzureGitRepo_Update_DoesNotSwallowErrorFromFailedCreateCall(t *testing.
ctrl := gomock.NewController(t)
defer ctrl.Finish()
- resourceData := schema.TestResourceDataRaw(t, resourceAzureGitRepository().Schema, nil)
- flattenAzureGitRepository(resourceData, &testAzureGitRepository)
+ resourceData := schema.TestResourceDataRaw(t, resourceGitRepository().Schema, nil)
+ resourceData.SetId(testAzureGitRepository.Id.String())
+ flattenGitRepository(resourceData, &testAzureGitRepository)
configureCleanInitialization(resourceData)
reposClient := azdosdkmocks.NewMockGitClient(ctrl)
@@ -94,7 +96,7 @@ func TestAzureGitRepo_Update_DoesNotSwallowErrorFromFailedCreateCall(t *testing.
Return(nil, errors.New("UpdateAzureGitRepository() Failed")).
Times(1)
- err := resourceAzureGitRepositoryUpdate(resourceData, clients)
+ err := resourceGitRepositoryUpdate(resourceData, clients)
require.Regexp(t, ".*UpdateAzureGitRepository\\(\\) Failed$", err.Error())
}
@@ -116,15 +118,43 @@ func TestAzureGitRepo_FlattenExpand_RoundTrip(t *testing.T) {
repoName := "name"
gitRepo := git.GitRepository{Id: &repoID, Name: &repoName, Project: &project}
- resourceData := schema.TestResourceDataRaw(t, resourceAzureGitRepository().Schema, nil)
- flattenAzureGitRepository(resourceData, &gitRepo)
+ resourceData := schema.TestResourceDataRaw(t, resourceGitRepository().Schema, nil)
+ resourceData.SetId(gitRepo.Id.String())
+ flattenGitRepository(resourceData, &gitRepo)
+
+ expandedGitRepo, repoInitialization, expandedProjectID, err := expandGitRepository(resourceData)
+
+ require.Nil(t, err)
+ require.NotNil(t, expandedGitRepo)
+ require.NotNil(t, expandedGitRepo.Id)
+ require.Equal(t, *expandedGitRepo.Id, repoID)
+ require.NotNil(t, expandedProjectID)
+ require.Equal(t, *expandedProjectID, projectID)
+ require.Nil(t, repoInitialization)
+}
+
+func TestAzureGitRepo_FlattenExpandInitialization_RoundTrip(t *testing.T) {
+ projectID := uuid.New()
+ project := core.TeamProjectReference{Id: &projectID}
+
+ repoID := uuid.New()
+ repoName := "name"
+ gitRepo := git.GitRepository{Id: &repoID, Name: &repoName, Project: &project}
+
+ resourceData := schema.TestResourceDataRaw(t, resourceGitRepository().Schema, nil)
+ resourceData.SetId(gitRepo.Id.String())
+ flattenGitRepository(resourceData, &gitRepo)
configureCleanInitialization(resourceData)
- expandedGitRepo, repoInitialization, expandedProjectID, err := expandAzureGitRepository(resourceData)
+ expandedGitRepo, repoInitialization, expandedProjectID, err := expandGitRepository(resourceData)
require.Nil(t, err)
+ require.NotNil(t, expandedGitRepo)
+ require.NotNil(t, expandedGitRepo.Id)
require.Equal(t, *expandedGitRepo.Id, repoID)
+ require.NotNil(t, expandedProjectID)
require.Equal(t, *expandedProjectID, projectID)
+ require.NotNil(t, repoInitialization)
require.Equal(t, repoInitialization.initType, "Clean")
require.Equal(t, repoInitialization.sourceType, "")
require.Equal(t, repoInitialization.sourceURL, "")
@@ -142,7 +172,7 @@ func TestAzureGitRepo_Read_DoesNotSwallowErrorFromFailedReadCall(t *testing.T) {
Ctx: context.Background(),
}
- resourceData := schema.TestResourceDataRaw(t, resourceAzureGitRepository().Schema, nil)
+ resourceData := schema.TestResourceDataRaw(t, resourceGitRepository().Schema, nil)
resourceData.SetId("an-id")
resourceData.Set("project_id", "a-project")
@@ -153,7 +183,7 @@ func TestAzureGitRepo_Read_DoesNotSwallowErrorFromFailedReadCall(t *testing.T) {
Return(nil, fmt.Errorf("GetRepository() Failed")).
Times(1)
- err := resourceAzureGitRepositoryRead(resourceData, clients)
+ err := resourceGitRepositoryRead(resourceData, clients)
require.Contains(t, err.Error(), "GetRepository() Failed")
}
@@ -168,7 +198,7 @@ func TestAzureGitRepo_Read_UsesIdIfSet(t *testing.T) {
Ctx: context.Background(),
}
- resourceData := schema.TestResourceDataRaw(t, resourceAzureGitRepository().Schema, nil)
+ resourceData := schema.TestResourceDataRaw(t, resourceGitRepository().Schema, nil)
resourceData.SetId("an-id")
resourceData.Set("project_id", "a-project")
@@ -179,14 +209,14 @@ func TestAzureGitRepo_Read_UsesIdIfSet(t *testing.T) {
Return(nil, fmt.Errorf("error")).
Times(1)
- resourceAzureGitRepositoryRead(resourceData, clients)
+ resourceGitRepositoryRead(resourceData, clients)
}
func TestAzureGitRepo_Delete_ChecksForValidUUID(t *testing.T) {
- resourceData := schema.TestResourceDataRaw(t, resourceAzureGitRepository().Schema, nil)
+ resourceData := schema.TestResourceDataRaw(t, resourceGitRepository().Schema, nil)
resourceData.SetId("not-a-uuid-id")
- err := resourceAzureGitRepositoryDelete(resourceData, &config.AggregatedClient{})
+ err := resourceGitRepositoryDelete(resourceData, &config.AggregatedClient{})
require.NotNil(t, err)
require.Contains(t, err.Error(), "Invalid repositoryId UUID")
}
@@ -201,7 +231,7 @@ func TestAzureGitRepo_Delete_DoesNotSwallowErrorFromFailedDeleteCall(t *testing.
Ctx: context.Background(),
}
- resourceData := schema.TestResourceDataRaw(t, resourceAzureGitRepository().Schema, nil)
+ resourceData := schema.TestResourceDataRaw(t, resourceGitRepository().Schema, nil)
id := uuid.New()
resourceData.SetId(id.String())
@@ -212,7 +242,7 @@ func TestAzureGitRepo_Delete_DoesNotSwallowErrorFromFailedDeleteCall(t *testing.
Return(fmt.Errorf("DeleteRepository() Failed")).
Times(1)
- err := resourceAzureGitRepositoryDelete(resourceData, clients)
+ err := resourceGitRepositoryDelete(resourceData, clients)
require.Contains(t, err.Error(), "DeleteRepository() Failed")
}
@@ -227,7 +257,7 @@ func TestAzureGitRepo_Read_UsesNameIfIdNotSet(t *testing.T) {
Ctx: context.Background(),
}
- resourceData := schema.TestResourceDataRaw(t, resourceAzureGitRepository().Schema, nil)
+ resourceData := schema.TestResourceDataRaw(t, resourceGitRepository().Schema, nil)
resourceData.Set("name", "a-name")
resourceData.Set("project_id", "a-project")
@@ -238,7 +268,7 @@ func TestAzureGitRepo_Read_UsesNameIfIdNotSet(t *testing.T) {
Return(nil, fmt.Errorf("error")).
Times(1)
- resourceAzureGitRepositoryRead(resourceData, clients)
+ resourceGitRepositoryRead(resourceData, clients)
}
/**
@@ -255,7 +285,7 @@ func TestAccAzureGitRepo_CreateAndUpdate(t *testing.T) {
projectName := testhelper.TestAccResourcePrefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
gitRepoNameFirst := testhelper.TestAccResourcePrefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
gitRepoNameSecond := testhelper.TestAccResourcePrefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
- tfRepoNode := "azuredevops_azure_git_repository.gitrepo"
+ tfRepoNode := "azuredevops_git_repository.gitrepo"
resource.Test(t, resource.TestCase{
PreCheck: func() { testhelper.TestAccPreCheck(t, nil) },
@@ -300,7 +330,7 @@ func testAccCheckAzureGitRepoResourceExists(expectedName string) resource.TestCh
return func(s *terraform.State) error {
clients := testAccProvider.Meta().(*config.AggregatedClient)
- gitRepo, ok := s.RootModule().Resources["azuredevops_azure_git_repository.gitrepo"]
+ gitRepo, ok := s.RootModule().Resources["azuredevops_git_repository.gitrepo"]
if !ok {
return fmt.Errorf("Did not find a repo definition in the TF state")
}
@@ -308,7 +338,7 @@ func testAccCheckAzureGitRepoResourceExists(expectedName string) resource.TestCh
repoID := gitRepo.Primary.ID
projectID := gitRepo.Primary.Attributes["project_id"]
- repo, err := azureGitRepositoryRead(clients, repoID, "", projectID)
+ repo, err := gitRepositoryRead(clients, repoID, "", projectID)
if err != nil {
return err
}
@@ -326,7 +356,7 @@ func testAccAzureGitRepoCheckDestroy(s *terraform.State) error {
// verify that every repository referenced in the state does not exist in AzDO
for _, resource := range s.RootModule().Resources {
- if resource.Type != "azuredevops_azure_git_repository" {
+ if resource.Type != "azuredevops_git_repository" {
continue
}
@@ -334,7 +364,7 @@ func testAccAzureGitRepoCheckDestroy(s *terraform.State) error {
projectID := resource.Primary.Attributes["project_id"]
// indicates the git repository still exists - this should fail the test
- if _, err := azureGitRepositoryRead(clients, repoID, "", projectID); err == nil {
+ if _, err := gitRepositoryRead(clients, repoID, "", projectID); err == nil {
return fmt.Errorf("repository with ID %s should not exist", repoID)
}
}
@@ -347,7 +377,7 @@ func testAccAzureGitRepoCheckDestroy(s *terraform.State) error {
func TestAccAzureGitRepo_RepoInitialization_Clean(t *testing.T) {
projectName := testhelper.TestAccResourcePrefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
gitRepoName := testhelper.TestAccResourcePrefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
- tfRepoNode := "azuredevops_azure_git_repository.gitrepo"
+ tfRepoNode := "azuredevops_git_repository.gitrepo"
resource.Test(t, resource.TestCase{
PreCheck: func() { testhelper.TestAccPreCheck(t, nil) },
@@ -372,7 +402,7 @@ func TestAccAzureGitRepo_RepoInitialization_Clean(t *testing.T) {
func TestAccAzureGitRepo_RepoInitialization_Uninitialized(t *testing.T) {
projectName := testhelper.TestAccResourcePrefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
gitRepoName := testhelper.TestAccResourcePrefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
- tfRepoNode := "azuredevops_azure_git_repository.gitrepo"
+ tfRepoNode := "azuredevops_git_repository.gitrepo"
resource.Test(t, resource.TestCase{
PreCheck: func() { testhelper.TestAccPreCheck(t, nil) },
diff --git a/azuredevops/utils/converter/converter.go b/azuredevops/utils/converter/converter.go
index 3caf428b..2cc4d177 100644
--- a/azuredevops/utils/converter/converter.go
+++ b/azuredevops/utils/converter/converter.go
@@ -24,6 +24,11 @@ func Int(value int) *int {
return &value
}
+// UInt64 Get a pointer to an uint64 value
+func UInt64(value uint64) *uint64 {
+ return &value
+}
+
// ToString Given a pointer return its value, or a default value of the poitner is nil
func ToString(value *string, defaultValue string) string {
if value != nil {
diff --git a/azuredevops/utils/testhelper/dataGenerator.go b/azuredevops/utils/testhelper/dataGenerator.go
new file mode 100644
index 00000000..1ec8f4d7
--- /dev/null
+++ b/azuredevops/utils/testhelper/dataGenerator.go
@@ -0,0 +1,9 @@
+package testhelper
+
+import "github.com/google/uuid"
+
+// CreateUUID creates a new UUID
+func CreateUUID() *uuid.UUID {
+ val := uuid.New()
+ return &val
+}
diff --git a/azuredevops/utils/testhelper/hcl.go b/azuredevops/utils/testhelper/hcl.go
index f849b666..0c29fe14 100644
--- a/azuredevops/utils/testhelper/hcl.go
+++ b/azuredevops/utils/testhelper/hcl.go
@@ -8,7 +8,7 @@ import (
// TestAccAzureGitRepoResource HCL describing an AzDO GIT repository resource
func TestAccAzureGitRepoResource(projectName string, gitRepoName string, initType string) string {
azureGitRepoResource := fmt.Sprintf(`
-resource "azuredevops_azure_git_repository" "gitrepo" {
+resource "azuredevops_git_repository" "gitrepo" {
project_id = azuredevops_project.project.id
name = "%s"
initialization {
diff --git a/docs/testing.md b/docs/testing.md
index fb732b76..8c9419b1 100644
--- a/docs/testing.md
+++ b/docs/testing.md
@@ -32,7 +32,7 @@ func TestAccAzureGitRepo_CreateAndUpdate(t *testing.T) {
projectName := testhelper.TestAccResourcePrefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
gitRepoNameFirst := testhelper.TestAccResourcePrefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
gitRepoNameSecond := testhelper.TestAccResourcePrefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
- tfRepoNode := "azuredevops_azure_git_repository.gitrepo"
+ tfRepoNode := "azuredevops_git_repository.gitrepo"
...
}
diff --git a/examples/azdo-based-cicd/main.tf b/examples/azdo-based-cicd/main.tf
index dd25b388..a5bda0a5 100644
--- a/examples/azdo-based-cicd/main.tf
+++ b/examples/azdo-based-cicd/main.tf
@@ -42,8 +42,8 @@ resource "azuredevops_build_definition" "build" {
repository {
repo_type = "TfsGit"
- repo_name = azuredevops_azure_git_repository.repository.name
- branch_name = azuredevops_azure_git_repository.repository.default_branch
+ repo_name = azuredevops_git_repository.repository.name
+ branch_name = azuredevops_git_repository.repository.default_branch
yml_path = "azure-pipelines.yml"
}
@@ -76,7 +76,7 @@ resource "azuredevops_variable_group" "vg" {
}
// This section configures an Azure DevOps Git Repository with branch policies
-resource "azuredevops_azure_git_repository" "repository" {
+resource "azuredevops_git_repository" "repository" {
project_id = azuredevops_project.project.id
name = "Sample Repo"
initialization {
@@ -100,8 +100,8 @@ resource "azuredevops_serviceendpoint_azurerm" "endpoint1" {
# https://github.com/microsoft/terraform-provider-azuredevops/issues/83
# resource "azuredevops_policy_build" "p1" {
# scope {
-# repository_id = azuredevops_azure_git_repository.repository.id
-# repository_ref = azuredevops_azure_git_repository.repository.default_branch
+# repository_id = azuredevops_git_repository.repository.id
+# repository_ref = azuredevops_git_repository.repository.default_branch
# match_type = "Exact"
# }
# settings {
@@ -111,8 +111,8 @@ resource "azuredevops_serviceendpoint_azurerm" "endpoint1" {
# }
# resource "azuredevops_policy_min_reviewers" "p1" {
# scope {
-# repository_id = azuredevops_azure_git_repository.repository.id
-# repository_ref = azuredevops_azure_git_repository.repository.default_branch
+# repository_id = azuredevops_git_repository.repository.id
+# repository_ref = azuredevops_git_repository.repository.default_branch
# match_type = "Exact"
# }
# settings {
diff --git a/website/docs/d/data_git_repositories.html.markdown b/website/docs/d/data_git_repositories.html.markdown
new file mode 100644
index 00000000..20d381e0
--- /dev/null
+++ b/website/docs/d/data_git_repositories.html.markdown
@@ -0,0 +1,85 @@
+# Data Source: azuredevops_git_repositories
+
+Use this data source to access information about an existing Projects within Azure DevOps.
+
+## Example Usage
+
+```hcl
+
+# Make sure to set the following environment variables:
+# AZDO_PERSONAL_ACCESS_TOKEN
+# AZDO_ORG_SERVICE_URL
+provider "azuredevops" {
+ version = ">= 0.0.1"
+}
+
+# Load all projects of an organization,
+# that are accessible by the current user
+data "azuredevops_projects" "tf-projects" {
+}
+
+# Build a local map, to access projects by name
+locals {
+ project_map = {
+ for project in data.azuredevops_projects.tf-projects.projects : project["name"] => project
+ }
+}
+
+# Load all Git repositories of an organization,
+# which are accessible for the current user
+data "azuredevops_git_repositories" "tf-git-repos-all" {
+}
+
+output "out-tf-git-repos-all" {
+ value = data.azuredevops_git_repositories.tf-git-repos-all.repositories
+}
+
+# Build a local map, to access Git repositories by name
+locals {
+ repo_map = {
+ for repo in data.azuredevops_git_repositories.tf-git-repos-all.repositories : repo["name"] => repo
+ }
+}
+
+# Load all Git repositories of a project,
+# which are accessible for the current user
+data "azuredevops_git_repositories" "tf-git-repos-project" {
+ project_id = local.project_map[var.project_name].project_id
+}
+
+# Load a specific Git repository by name
+data "azuredevops_git_repositories" "tf-git-repos-project-reponame" {
+ project_id = local.project_map[var.project_name].project_id
+ name = var.git_repo_name
+}
+
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+- `project_id` - (Optional) ID of project to list Git repositories
+- `name` - (Optional) Name of the Git repository to retrieve; requires `project_id` to be specified as well
+- `include_hidden` - (Optional, default: false)
+
+DataSource without specifying any arguments will return all Git repositories of an organization.
+
+## Attributes Reference
+
+The following attributes are exported:
+
+- `repositories` - A list of existing projects in your Azure DevOps Organization with details about every project which includes:
+
+ - `id` - Git repository identifier.
+ - `name` - Git repository name.
+ - `url` - Details REST API endpoint for the Git Repository.
+ - `ssh_url` - SSH Url to clone the Git repository
+ - `web_url` - Url of the Git repository web view
+ - `remote_url` - HTTPS Url to clone the Git repository
+ - `project_id` - Project identifier to which the Git repository belongs.
+ - `size` - Compressed size (bytes) of the repository.
+
+## Relevant Links
+
+- [Azure DevOps Service REST API 5.1 - Git API](https://docs.microsoft.com/en-us/rest/api/azure/devops/git/?view=azure-devops-rest-5.1)
diff --git a/website/docs/r/azure_git_repository.html.markdown b/website/docs/r/azure_git_repository.html.markdown
index 07bc990d..58f9da76 100644
--- a/website/docs/r/azure_git_repository.html.markdown
+++ b/website/docs/r/azure_git_repository.html.markdown
@@ -1,8 +1,10 @@
-# azuredevops_azure_git_repository
+# azuredevops_git_repository
Manages a git repository within Azure DevOps.
## Example Usage
+### Create Git repository
+
```hcl
resource "azuredevops_project" "project" {
project_name = "Sample Project"
@@ -11,7 +13,7 @@ resource "azuredevops_project" "project" {
work_item_template = "Agile"
}
-resource "azuredevops_azure_git_repository" "repo" {
+resource "azuredevops_git_repository" "repo" {
project_id = azuredevops_project.project.id
name = "Sample Empty Git Repository"
initialization {
@@ -19,16 +21,14 @@ resource "azuredevops_azure_git_repository" "repo" {
}
```
+### Create Fork of another Azure DevOps Git repository
```hcl
-resource "azuredevops_azure_git_repository" "repo" {
+resource "azuredevops_git_repository" "repo" {
project_id = azuredevops_project.project.id
name = "Sample Fork an Existing Repository"
- initialization {
- init_type = "Fork"
- source_type = ""
- source_url = ""
- }
+ parent_id = azuredevops_git_repository.parent.id
+}
```
## Argument Reference
@@ -37,26 +37,27 @@ The following arguments are supported:
* `project_id` - (Required) The project ID or project name.
* `name` - (Required) The name of the git repository.
-* `initialization` - (Required) An `initialization` block as documented below.
+* `parent_id` - (Optional) The ID of a Git project from which a fork is to be created.
+* `initialization` - (Optional) An `initialization` block as documented below.
`initialization` block supports the following:
-* `init_type` - (Required) The type of repository to create. Valid values: `Uninitialized`, `Clean`, `Fork`, or `Import`. Defaults to `Uninitialized`.
-* `source_type` - (Optional) Type type of the source repository. Used if the init type is `Fork` or `Import`.
-* `source_url` - (Optional) The url of the source repository. Used if the init type is `Fork` or `Import`.
+* `init_type` - (Required) The type of repository to create. Valid values: `Uninitialized`, `Clean`, or `Import`. Defaults to `Uninitialized`.
+* `source_type` - (Optional) Type type of the source repository. Used if the `init_type` is `Import`.
+* `source_url` - (Optional) The URL of the source repository. Used if the `init_type` is `Import`.
## Attributes Reference
In addition to all arguments above, except `initialization`, the following attributes are exported:
-* `id` - The ID of the agent pool.
+* `id` - The ID of the Git repository.
* `default_branch` - The name of the default branch.
* `is_fork` - True if the repository was created as a fork.
-* `remote_url` - If `init_type` is `Fork` the url of the remote repository.
+* `remote_url` - Git HTTPS URL of the repository
* `size` - Size in bytes.
-* `ssh_url` - Git SSH Url of the repository.
-* `url` - Git Url of the repository.
+* `ssh_url` - Git SSH URL of the repository.
+* `url` - REST API URL of the repository.
* `web_url` - Web link to the repository.
## Relevant Links
diff --git a/website/docs/r/build_definition.html.markdown b/website/docs/r/build_definition.html.markdown
index f0b0ee6f..613f96ad 100644
--- a/website/docs/r/build_definition.html.markdown
+++ b/website/docs/r/build_definition.html.markdown
@@ -11,7 +11,7 @@ resource "azuredevops_project" "project" {
work_item_template = "Agile"
}
-resource "azuredevops_azure_git_repository" "repository" {
+resource "azuredevops_git_repository" "repository" {
project_id = azuredevops_project.project.id
name = "Sample Repository"
initialization {
@@ -26,8 +26,8 @@ resource "azuredevops_build_definition" "build" {
repository {
repo_type = "TfsGit"
- repo_name = azuredevops_azure_git_repository.repository.name
- branch_name = azuredevops_azure_git_repository.repository.default_branch
+ repo_name = azuredevops_git_repository.repository.name
+ branch_name = azuredevops_git_repository.repository.default_branch
yml_path = "azure-pipelines.yml"
}
diff --git a/website/index.html.markdown b/website/index.html.markdown
index 40f9ed53..3c24a118 100644
--- a/website/index.html.markdown
+++ b/website/index.html.markdown
@@ -10,6 +10,7 @@ The Azure DevOps provider can be used to configure Azure DevOps project in [Micr
- [azuredevops_group](docs/d/data_group.html.markdown)
- [azuredevops_project](docs/d/data_project.html.markdown)
+- [azuredevops_git_repositories](docs/d/data_git_repositories.html.markdown)
## Resources