Skip to content

Commit 9f8fe2d

Browse files
committed
New Resource gitlab_project_issue
This is an initial version of this resource. It mainly covers the most simple CRUD functions. Additional issue API endpoints like subscriptions, todos, time estimation, merge request and issue relations, ... are NOT yet supported. I believe that the state as-is in this change set already provides a great set of value for potentially interested users. I imagine that the main use case for this is to bootstrap a project with some getting started / welcome issues and not to track time etc. Refs #746
1 parent fb2e42d commit 9f8fe2d

File tree

8 files changed

+1304
-1
lines changed

8 files changed

+1304
-1
lines changed

docs/resources/project_issue.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "gitlab_project_issue Resource - terraform-provider-gitlab"
4+
subcategory: ""
5+
description: |-
6+
This resource allows you to create and manage GitLab Project Issues.
7+
During a terraform destroy this resource will close the issue.
8+
Set the deleteondestroy flag to true to delete the issue instead of closing it.
9+
Experimental: while the base functionality of this resource works, it may be subject to minor change.
10+
Upstream API: GitLab API docs https://docs.gitlab.com/ee/api/issues.html
11+
---
12+
13+
# gitlab_project_issue (Resource)
14+
15+
This resource allows you to create and manage GitLab Project Issues.
16+
17+
During a terraform destroy this resource will close the issue.
18+
Set the delete_on_destroy flag to true to delete the issue instead of closing it.
19+
20+
**Experimental**: while the base functionality of this resource works, it may be subject to minor change.
21+
22+
**Upstream API:** [GitLab API docs](https://docs.gitlab.com/ee/api/issues.html)
23+
24+
## Example Usage
25+
26+
```terraform
27+
resource "gitlab_project" "foo" {
28+
name = "example project"
29+
description = "Lorem Ipsum"
30+
visibility_level = "public"
31+
}
32+
33+
resource "gitlab_project_issue" "welcome_issue" {
34+
project = gitlab_project.foo.id
35+
title = "Welcome!"
36+
description = <<EOT
37+
Welcome to the ${gitlab_project.foo.name} project!
38+
39+
EOT
40+
discussion_locked = true
41+
}
42+
43+
output "welcome_issue_web_url" {
44+
value = data.gitlab_project_issue.web_url
45+
}
46+
```
47+
48+
<!-- schema generated by tfplugindocs -->
49+
## Schema
50+
51+
### Required
52+
53+
- **project** (String) The name or ID of the project.
54+
- **title** (String) The title of the issue.
55+
56+
### Optional
57+
58+
- **assignee_ids** (Set of Number) The IDs of the users to assign the issue to.
59+
- **closed_at** (String) When the issue was closed. Date time string, ISO 8601 formatted, for example 2016-03-11T03:45:40Z.
60+
- **closed_by_user_id** (Number) The ID of the user that closed the issue. Use `gitlab_user` data source to get more information about the user.
61+
- **confidential** (Boolean) Set an issue to be confidential.
62+
- **created_at** (String) When the issue was created. Date time string, ISO 8601 formatted, for example 2016-03-11T03:45:40Z. Requires administrator or project/group owner rights.
63+
- **delete_on_destroy** (Boolean) Whether the issue is deleted instead of closed during destroy.
64+
- **description** (String) The description of an issue. Limited to 1,048,576 characters.
65+
- **discussion_locked** (Boolean) Whether the issue is locked for discussions or not.
66+
- **discussion_to_resolve** (String) The ID of a discussion to resolve. This fills out the issue with a default description and mark the discussion as resolved. Use in combination with merge_request_to_resolve_discussions_of.
67+
- **due_date** (String) The due date. Date time string in the format YYYY-MM-DD, for example 2016-03-11.
68+
**Note:** removing a due date is currently not supported, see https://github.com/xanzy/go-gitlab/issues/1384 for details.
69+
- **epic_issue_id** (Number) The ID of the epic issue.
70+
- **human_time_estimate** (String) The human-readable time estimate of the issue.
71+
- **human_total_time_spent** (String) The human-readable total time spent of the issue.
72+
- **id** (String) The ID of this resource.
73+
- **iid** (Number) The internal ID of the project's issue.
74+
- **issue_type** (String) The type of issue. Valid values are: `issue`, `incident`, `test_case`.
75+
- **labels** (Set of String) The labels of an issue.
76+
- **links** (Map of String) The links of the issue.
77+
- **merge_request_to_resolve_discussions_of** (Number) The IID of a merge request in which to resolve all issues. This fills out the issue with a default description and mark all discussions as resolved. When passing a description or title, these values take precedence over the default values.
78+
- **milestone_id** (Number) The global ID of a milestone to assign issue. To find the milestone_id associated with a milestone, view an issue with the milestone assigned and use the API to retrieve the issue's details.
79+
- **references** (Map of String) The references of the issue.
80+
- **state** (String) The state of the issue. Valid values are: `opened`, `closed`.
81+
- **task_completion_status** (Block List, Max: 1) The task completion status. It's always a one element list. (see [below for nested schema](#nestedblock--task_completion_status))
82+
- **time_estimate** (Number) The time estimate of the issue.
83+
- **total_time_spent** (Number) The total time spent of the issue.
84+
- **updated_at** (String) When the issue was updated. Date time string, ISO 8601 formatted, for example 2016-03-11T03:45:40Z.
85+
- **weight** (Number) The weight of the issue. Valid values are greater than or equal to 0.
86+
87+
### Read-Only
88+
89+
- **author_id** (Number) The ID of the author of the issue. Use `gitlab_user` data source to get more information about the user.
90+
- **downvotes** (Number) The number of downvotes the issue has received.
91+
- **epic_id** (Number) ID of the epic to add the issue to. Valid values are greater than or equal to 0.
92+
- **external_id** (String) The external ID of the issue.
93+
- **issue_id** (Number) The instance-wide ID of the issue.
94+
- **issue_link_id** (Number) The ID of the issue link.
95+
- **merge_requests_count** (Number) The number of merge requests associated with the issue.
96+
- **moved_to_id** (Number) The ID of the issue that was moved to.
97+
- **subscribed** (Boolean) Whether the authenticated user is subscribed to the issue or not.
98+
- **upvotes** (Number) The number of upvotes the issue has received.
99+
- **user_notes_count** (Number) The number of user notes on the issue.
100+
- **web_url** (String) The web URL of the issue.
101+
102+
<a id="nestedblock--task_completion_status"></a>
103+
### Nested Schema for `task_completion_status`
104+
105+
Optional:
106+
107+
- **completed_count** (Number) The number of tasks that are completed.
108+
- **count** (Number) The number of tasks.
109+
110+
## Import
111+
112+
Import is supported using the following syntax:
113+
114+
```shell
115+
# You can import this resource with an id made up of `{project-id}:{issue-id}`, e.g.
116+
terraform import gitlab_project_issue.welcome_issue 42:1
117+
```
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# You can import this resource with an id made up of `{project-id}:{issue-id}`, e.g.
2+
terraform import gitlab_project_issue.welcome_issue 42:1
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
resource "gitlab_project" "foo" {
2+
name = "example project"
3+
description = "Lorem Ipsum"
4+
visibility_level = "public"
5+
}
6+
7+
resource "gitlab_project_issue" "welcome_issue" {
8+
project = gitlab_project.foo.id
9+
title = "Welcome!"
10+
description = <<EOT
11+
Welcome to the ${gitlab_project.foo.name} project!
12+
13+
EOT
14+
discussion_locked = true
15+
}
16+
17+
output "welcome_issue_web_url" {
18+
value = data.gitlab_project_issue.web_url
19+
}

internal/provider/helper_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import (
55
"os"
66
"strings"
77
"testing"
8+
"time"
89

910
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
1011
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
1112
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
13+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
1214
"github.com/onsi/gomega"
1315
"github.com/xanzy/go-gitlab"
1416
)
@@ -240,6 +242,25 @@ func testAccAddProjectMembers(t *testing.T, pid interface{}, users []*gitlab.Use
240242
}
241243
}
242244

245+
func testAccCreateProjectIssues(t *testing.T, pid interface{}, n int) []*gitlab.Issue {
246+
t.Helper()
247+
248+
dueDate := gitlab.ISOTime(time.Now().Add(time.Hour))
249+
var issues []*gitlab.Issue
250+
for i := 0; i < n; i++ {
251+
issue, _, err := testGitlabClient.Issues.CreateIssue(pid, &gitlab.CreateIssueOptions{
252+
Title: gitlab.String(fmt.Sprintf("Issue %d", i)),
253+
Description: gitlab.String(fmt.Sprintf("Description %d", i)),
254+
DueDate: &dueDate,
255+
})
256+
if err != nil {
257+
t.Fatalf("could not create test issue: %v", err)
258+
}
259+
issues = append(issues, issue)
260+
}
261+
return issues
262+
}
263+
243264
// testAccAddGroupMembers is a test helper for adding users as members of a group.
244265
// It assumes the group will be destroyed at the end of the test and will not cleanup members.
245266
func testAccAddGroupMembers(t *testing.T, gid interface{}, users []*gitlab.User) {
@@ -256,6 +277,22 @@ func testAccAddGroupMembers(t *testing.T, gid interface{}, users []*gitlab.User)
256277
}
257278
}
258279

280+
func testAccAddProjectMilestone(t *testing.T, pid interface{}) *gitlab.Milestone {
281+
t.Helper()
282+
283+
milestone, _, err := testGitlabClient.Milestones.CreateMilestone(pid, &gitlab.CreateMilestoneOptions{Title: gitlab.String("Test Milestone")})
284+
if err != nil {
285+
t.Fatalf("failed to create milestone during test for project %v: %v", pid, err)
286+
}
287+
t.Cleanup(func() {
288+
_, err := testGitlabClient.Milestones.DeleteMilestone(pid, milestone.ID)
289+
if err != nil {
290+
t.Fatalf("failed to delete milestone %d during test for project %v: %v", milestone.ID, pid, err)
291+
}
292+
})
293+
return milestone
294+
}
295+
259296
// testAccGitlabProjectContext encapsulates a GitLab client and test project to be used during an
260297
// acceptance test.
261298
type testAccGitlabProjectContext struct {
@@ -292,3 +329,11 @@ func testAccGitlabProjectStart(t *testing.T) testAccGitlabProjectContext {
292329
project: project,
293330
}
294331
}
332+
333+
// testCheckResourceAttrLazy works like resource.TestCheckResourceAttr, but lazy evaluates the value parameter.
334+
// See also: resource.TestCheckResourceAttrPtr.
335+
func testCheckResourceAttrLazy(name string, key string, value func() string) resource.TestCheckFunc {
336+
return func(s *terraform.State) error {
337+
return resource.TestCheckResourceAttr(name, key, value())(s)
338+
}
339+
}

0 commit comments

Comments
 (0)