Skip to content

Commit 71dd108

Browse files
authored
Merge pull request #1198 from Shocktrooper/RepoTree
Added code for Repository Tree Datasource
2 parents 394f4ff + f888fd5 commit 71dd108

File tree

7 files changed

+273
-10
lines changed

7 files changed

+273
-10
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "gitlab_repository_tree Data Source - terraform-provider-gitlab"
4+
subcategory: ""
5+
description: |-
6+
The gitlab_repository_tree data source allows details of directories and files in a repository to be retrieved.
7+
Upstream API: GitLab REST API docs https://docs.gitlab.com/ee/api/repositories.html#list-repository-tree
8+
---
9+
10+
# gitlab_repository_tree (Data Source)
11+
12+
The `gitlab_repository_tree` data source allows details of directories and files in a repository to be retrieved.
13+
14+
**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/repositories.html#list-repository-tree)
15+
16+
## Example Usage
17+
18+
```terraform
19+
data "gitlab_repository_tree" "this" {
20+
project = "example"
21+
ref = "main"
22+
path = "ExampleSubFolder"
23+
recursive = true
24+
}
25+
```
26+
27+
<!-- schema generated by tfplugindocs -->
28+
## Schema
29+
30+
### Required
31+
32+
- `project` (String) The ID or full path of the project owned by the authenticated user.
33+
- `ref` (String) The name of a repository branch or tag.
34+
35+
### Optional
36+
37+
- `path` (String) The path inside repository. Used to get content of subdirectories.
38+
- `recursive` (Boolean) Boolean value used to get a recursive tree (false by default).
39+
40+
### Read-Only
41+
42+
- `id` (String) The ID of this resource.
43+
- `tree` (List of Object) The list of files/directories returned by the search (see [below for nested schema](#nestedatt--tree))
44+
45+
<a id="nestedatt--tree"></a>
46+
### Nested Schema for `tree`
47+
48+
Read-Only:
49+
50+
- `id` (String)
51+
- `mode` (String)
52+
- `name` (String)
53+
- `path` (String)
54+
- `type` (String)
55+
56+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
data "gitlab_repository_tree" "this" {
2+
project = "example"
3+
ref = "main"
4+
path = "ExampleSubFolder"
5+
recursive = true
6+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
"github.com/mitchellh/hashstructure"
10+
gitlab "github.com/xanzy/go-gitlab"
11+
)
12+
13+
var _ = registerDataSource("gitlab_repository_tree", func() *schema.Resource {
14+
return &schema.Resource{
15+
Description: `The ` + "`gitlab_repository_tree`" + ` data source allows details of directories and files in a repository to be retrieved.
16+
17+
**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/repositories.html#list-repository-tree)`,
18+
19+
ReadContext: dataSourceGitlabRepositoryTreeRead,
20+
Schema: map[string]*schema.Schema{
21+
"project": {
22+
Description: "The ID or full path of the project owned by the authenticated user.",
23+
Type: schema.TypeString,
24+
Required: true,
25+
},
26+
"ref": {
27+
Description: "The name of a repository branch or tag.",
28+
Type: schema.TypeString,
29+
Required: true,
30+
},
31+
"path": {
32+
Description: "The path inside repository. Used to get content of subdirectories.",
33+
Type: schema.TypeString,
34+
Optional: true,
35+
},
36+
"recursive": {
37+
Description: "Boolean value used to get a recursive tree (false by default).",
38+
Type: schema.TypeBool,
39+
Optional: true,
40+
},
41+
"tree": {
42+
Description: "The list of files/directories returned by the search",
43+
Type: schema.TypeList,
44+
Computed: true,
45+
Elem: &schema.Resource{
46+
Schema: map[string]*schema.Schema{
47+
"id": {
48+
Description: "The SHA-1 hash of the tree or blob in the repository.",
49+
Type: schema.TypeString,
50+
Computed: true,
51+
},
52+
"name": {
53+
Description: "Name of the blob or tree in the repository",
54+
Type: schema.TypeString,
55+
Computed: true,
56+
},
57+
"type": {
58+
Description: "Type of object in the repository. Can be either type tree or of type blob",
59+
Type: schema.TypeString,
60+
Computed: true,
61+
},
62+
"path": {
63+
Description: "Path of the object inside of the repository.",
64+
Type: schema.TypeString,
65+
Computed: true,
66+
},
67+
"mode": {
68+
Description: "Unix access mode of the file in the repository.",
69+
Type: schema.TypeString,
70+
Computed: true,
71+
},
72+
},
73+
},
74+
},
75+
},
76+
}
77+
})
78+
79+
func dataSourceGitlabRepositoryTreeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
80+
client := meta.(*gitlab.Client)
81+
project := d.Get("project").(string)
82+
83+
options := &gitlab.ListTreeOptions{
84+
ListOptions: gitlab.ListOptions{
85+
PerPage: 20,
86+
Page: 1,
87+
},
88+
Path: gitlab.String(d.Get("path").(string)),
89+
Ref: gitlab.String(d.Get("ref").(string)),
90+
Recursive: gitlab.Bool(d.Get("recursive").(bool)),
91+
}
92+
93+
var nodes []*gitlab.TreeNode
94+
for options.Page != 0 {
95+
96+
paginatedNodes, resp, err := client.Repositories.ListTree(project, options, gitlab.WithContext(ctx))
97+
if err != nil {
98+
return diag.FromErr(err)
99+
}
100+
101+
nodes = append(nodes, paginatedNodes...)
102+
103+
options.Page = resp.NextPage
104+
}
105+
106+
optionsHash, err := hashstructure.Hash(&options, nil)
107+
if err != nil {
108+
return diag.FromErr(err)
109+
}
110+
111+
d.SetId(fmt.Sprintf("%s:%d", project, optionsHash))
112+
if err := d.Set("tree", flattenGitlabRepositoryTree(project, nodes)); err != nil {
113+
return diag.Errorf("failed to set repository tree nodes to state: %v", err)
114+
}
115+
116+
return nil
117+
}
118+
119+
func flattenGitlabRepositoryTree(project string, treeNodes []*gitlab.TreeNode) []interface{} {
120+
treeNodeList := []interface{}{}
121+
122+
for _, node := range treeNodes {
123+
124+
values := map[string]interface{}{
125+
"id": project,
126+
"name": node.Name,
127+
"type": node.Type,
128+
"path": node.Path,
129+
"mode": node.Mode,
130+
}
131+
132+
treeNodeList = append(treeNodeList, values)
133+
}
134+
return treeNodeList
135+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//go:build acceptance
2+
// +build acceptance
3+
4+
package provider
5+
6+
import (
7+
"fmt"
8+
"testing"
9+
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
11+
)
12+
13+
func TestAccDataSourceGitlabRepositoryTree_basic(t *testing.T) {
14+
testProject := testAccCreateProject(t)
15+
testFile := testAccCreateProjectFile(t, testProject.ID, "content", "SomeFile", testProject.DefaultBranch)
16+
17+
resource.ParallelTest(t, resource.TestCase{
18+
ProviderFactories: providerFactories,
19+
Steps: []resource.TestStep{
20+
{
21+
Config: fmt.Sprintf(`
22+
data "gitlab_repository_tree" "this" {
23+
project = %[1]d
24+
ref = "%[2]s"
25+
}
26+
`, testProject.ID, testFile.Branch),
27+
Check: resource.ComposeTestCheckFunc(
28+
resource.TestCheckResourceAttr("data.gitlab_repository_tree.this", "tree.#", "2"),
29+
resource.TestCheckResourceAttr("data.gitlab_repository_tree.this", "tree.0.name", "README.md"),
30+
resource.TestCheckResourceAttr("data.gitlab_repository_tree.this", "tree.0.type", "blob"),
31+
resource.TestCheckResourceAttr("data.gitlab_repository_tree.this", "tree.0.path", "README.md"),
32+
resource.TestCheckResourceAttr("data.gitlab_repository_tree.this", "tree.0.mode", "100644"),
33+
34+
resource.TestCheckResourceAttr("data.gitlab_repository_tree.this", "tree.1.name", testFile.FilePath),
35+
resource.TestCheckResourceAttr("data.gitlab_repository_tree.this", "tree.1.type", "blob"),
36+
resource.TestCheckResourceAttr("data.gitlab_repository_tree.this", "tree.1.path", testFile.FilePath),
37+
resource.TestCheckResourceAttr("data.gitlab_repository_tree.this", "tree.1.mode", "100644"),
38+
),
39+
},
40+
},
41+
})
42+
}

internal/provider/helper_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,30 @@ func testAccCreateInstanceVariable(t *testing.T) *gitlab.InstanceVariable {
519519
return variable
520520
}
521521

522+
func testAccCreateProjectFile(t *testing.T, projectID int, fileContent string, filePath string, branch string) *gitlab.FileInfo {
523+
524+
file, _, err := testGitlabClient.RepositoryFiles.CreateFile(projectID, filePath, &gitlab.CreateFileOptions{
525+
Branch: &branch,
526+
Encoding: gitlab.String("base64"),
527+
Content: &fileContent,
528+
CommitMessage: gitlab.String(fmt.Sprintf("Random_Commit_Message_%d", acctest.RandInt())),
529+
})
530+
if err != nil {
531+
t.Fatal(err)
532+
}
533+
534+
t.Cleanup(func() {
535+
if _, err := testGitlabClient.RepositoryFiles.DeleteFile(projectID, filePath, &gitlab.DeleteFileOptions{
536+
Branch: &branch,
537+
CommitMessage: gitlab.String(fmt.Sprintf("Delete_Random_Commit_Message_%d", acctest.RandInt())),
538+
}); err != nil {
539+
t.Fatal(err)
540+
}
541+
})
542+
543+
return file
544+
}
545+
522546
// testAccGitlabProjectContext encapsulates a GitLab client and test project to be used during an
523547
// acceptance test.
524548
type testAccGitlabProjectContext struct {

internal/provider/resource_gitlab_repository_file.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ var _ = registerResource("gitlab_repository_file", func() *schema.Resource {
6969
Required: true,
7070
ForceNew: true,
7171
},
72+
"commit_message": {
73+
Description: "Commit message.",
74+
Type: schema.TypeString,
75+
Required: true,
76+
},
7277
"start_branch": {
7378
Description: "Name of the branch to start the new commit from.",
7479
Type: schema.TypeString,
@@ -84,11 +89,6 @@ var _ = registerResource("gitlab_repository_file", func() *schema.Resource {
8489
Type: schema.TypeString,
8590
Optional: true,
8691
},
87-
"commit_message": {
88-
Description: "Commit message.",
89-
Type: schema.TypeString,
90-
Required: true,
91-
},
9292
},
9393
gitlabRepositoryFileGetSchema(),
9494
),

internal/provider/schema_gitlab_repository_file.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ func gitlabRepositoryFileGetSchema() map[string]*schema.Schema {
1919
Required: true,
2020
ForceNew: true,
2121
},
22+
"content": {
23+
Description: "File content. If the content is not yet base64 encoded, it will be encoded automatically. No other encoding is currently supported, because of a [GitLab API bug](https://gitlab.com/gitlab-org/gitlab/-/issues/342430).",
24+
Type: schema.TypeString,
25+
Required: true,
26+
},
2227
"ref": {
2328
Description: "The name of branch, tag or commit.",
2429
Type: schema.TypeString,
@@ -39,11 +44,6 @@ func gitlabRepositoryFileGetSchema() map[string]*schema.Schema {
3944
Type: schema.TypeString,
4045
Computed: true,
4146
},
42-
"content": {
43-
Description: "File content. If the content is not yet base64 encoded, it will be encoded automatically. No other encoding is currently supported, because of a [GitLab API bug](https://gitlab.com/gitlab-org/gitlab/-/issues/342430).",
44-
Type: schema.TypeString,
45-
Required: true,
46-
},
4747
"content_sha256": {
4848
Description: "File content sha256 digest.",
4949
Type: schema.TypeString,

0 commit comments

Comments
 (0)