Skip to content

Commit da0f7ec

Browse files
authored
Merge pull request #899 from timofurrer/bugfix/issue-897
resource/gitlab_user: Add support for `deactivated` user state. Closes #897
2 parents 912223b + e292e1d commit da0f7ec

File tree

3 files changed

+156
-11
lines changed

3 files changed

+156
-11
lines changed

docs/resources/user.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ resource "gitlab_user" "example" {
5151
- **projects_limit** (Number) Integer, defaults to 0. Number of projects user can create.
5252
- **reset_password** (Boolean) Boolean, defaults to false. Send user password reset link.
5353
- **skip_confirmation** (Boolean) Boolean, defaults to true. Whether to skip confirmation.
54-
- **state** (String) String, defaults to 'active'. The state of the user account. Valid values are either 'active' or 'blocked'
54+
- **state** (String) String, defaults to 'active'. The state of the user account. Valid values are `active`, `deactivated`, `blocked`.
5555

5656
## Import
5757

internal/provider/resource_gitlab_user.go

+37-10
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ import (
1414
gitlab "github.com/xanzy/go-gitlab"
1515
)
1616

17+
var validUserStateValues = []string{
18+
"active",
19+
"deactivated",
20+
"blocked",
21+
}
22+
1723
var _ = registerResource("gitlab_user", func() *schema.Resource {
1824
return &schema.Resource{
1925
Description: "This resource allows you to create and manage GitLab users.\n" +
@@ -94,11 +100,11 @@ var _ = registerResource("gitlab_user", func() *schema.Resource {
94100
Optional: true,
95101
},
96102
"state": {
97-
Description: "String, defaults to 'active'. The state of the user account. Valid values are either 'active' or 'blocked'",
103+
Description: fmt.Sprintf("String, defaults to 'active'. The state of the user account. Valid values are %s.", renderValueListForDocs(validUserStateValues)),
98104
Type: schema.TypeString,
99105
Optional: true,
100106
Default: "active",
101-
ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice([]string{"active", "blocked"}, false)),
107+
ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice(validUserStateValues, false)),
102108
},
103109
},
104110
}
@@ -148,6 +154,12 @@ func resourceGitlabUserCreate(ctx context.Context, d *schema.ResourceData, meta
148154
if d.Get("state") == "blocked" {
149155
err := client.Users.BlockUser(user.ID)
150156

157+
if err != nil {
158+
return diag.FromErr(err)
159+
}
160+
} else if d.Get("state") == "deactivated" {
161+
err := client.Users.DeactivateUser(user.ID)
162+
151163
if err != nil {
152164
return diag.FromErr(err)
153165
}
@@ -224,18 +236,33 @@ func resourceGitlabUserUpdate(ctx context.Context, d *schema.ResourceData, meta
224236
}
225237

226238
if d.HasChange("state") {
227-
if d.Get("state") == "active" {
228-
err := client.Users.UnblockUser(id)
229-
239+
oldState, newState := d.GetChange("state")
240+
var err error
241+
// NOTE: yes, this can be written much more consice, however, for the sake of understanding the behavior,
242+
// of the API and the allowed state transitions of GitLab, let's keep it as-is and enjoy the readability.
243+
if newState == "active" && oldState == "blocked" {
244+
err = client.Users.UnblockUser(id)
245+
} else if newState == "active" && oldState == "deactivated" {
246+
err = client.Users.ActivateUser(id)
247+
} else if newState == "blocked" && oldState == "active" {
248+
err = client.Users.BlockUser(id)
249+
} else if newState == "blocked" && oldState == "deactivated" {
250+
err = client.Users.BlockUser(id)
251+
} else if newState == "deactivated" && oldState == "active" {
252+
err = client.Users.DeactivateUser(id)
253+
} else if newState == "deactivated" && oldState == "blocked" {
254+
// a blocked user cannot be deactivated, GitLab will return an error, like:
255+
// `403 Forbidden - A blocked user cannot be deactivated by the API`
256+
// we have to unblock the user first
257+
err = client.Users.UnblockUser(id)
230258
if err != nil {
231259
return diag.FromErr(err)
232260
}
233-
} else if d.Get("state") == "blocked" {
234-
err := client.Users.BlockUser(id)
261+
err = client.Users.DeactivateUser(id)
262+
}
235263

236-
if err != nil {
237-
return diag.FromErr(err)
238-
}
264+
if err != nil {
265+
return diag.FromErr(err)
239266
}
240267
}
241268

internal/provider/resource_gitlab_user_test.go

+118
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,108 @@ func TestAccGitlabUser_basic(t *testing.T) {
205205
"skip_confirmation",
206206
},
207207
},
208+
// Deactivate the user
209+
{
210+
Config: testAccGitlabUserConfigDeactivated(rInt),
211+
Check: resource.ComposeTestCheckFunc(
212+
testAccCheckGitlabUserExists("gitlab_user.foo", &user),
213+
testAccCheckGitlabUserAttributes(&user, &testAccGitlabUserExpectedAttributes{
214+
Email: fmt.Sprintf("listest%[email protected]", rInt),
215+
Username: fmt.Sprintf("listest%d", rInt),
216+
Name: fmt.Sprintf("foo %d", rInt),
217+
ProjectsLimit: 0,
218+
Admin: false,
219+
CanCreateGroup: false,
220+
External: false,
221+
State: "deactivated",
222+
}),
223+
),
224+
},
225+
// Re-activate the user
226+
{
227+
Config: testAccGitlabUserConfig(rInt),
228+
Check: resource.ComposeTestCheckFunc(
229+
testAccCheckGitlabUserExists("gitlab_user.foo", &user),
230+
testAccCheckGitlabUserAttributes(&user, &testAccGitlabUserExpectedAttributes{
231+
Email: fmt.Sprintf("listest%[email protected]", rInt),
232+
Username: fmt.Sprintf("listest%d", rInt),
233+
Name: fmt.Sprintf("foo %d", rInt),
234+
ProjectsLimit: 0,
235+
Admin: false,
236+
CanCreateGroup: false,
237+
External: false,
238+
State: "active",
239+
}),
240+
),
241+
},
242+
// Block the user
243+
{
244+
Config: testAccGitlabUserConfigBlocked(rInt),
245+
Check: resource.ComposeTestCheckFunc(
246+
testAccCheckGitlabUserExists("gitlab_user.foo", &user),
247+
testAccCheckGitlabUserAttributes(&user, &testAccGitlabUserExpectedAttributes{
248+
Email: fmt.Sprintf("listest%[email protected]", rInt),
249+
Username: fmt.Sprintf("listest%d", rInt),
250+
Name: fmt.Sprintf("foo %d", rInt),
251+
ProjectsLimit: 0,
252+
Admin: false,
253+
CanCreateGroup: false,
254+
External: false,
255+
State: "blocked",
256+
}),
257+
),
258+
},
259+
// Deactivate the user from blocked state
260+
{
261+
Config: testAccGitlabUserConfigDeactivated(rInt),
262+
Check: resource.ComposeTestCheckFunc(
263+
testAccCheckGitlabUserExists("gitlab_user.foo", &user),
264+
testAccCheckGitlabUserAttributes(&user, &testAccGitlabUserExpectedAttributes{
265+
Email: fmt.Sprintf("listest%[email protected]", rInt),
266+
Username: fmt.Sprintf("listest%d", rInt),
267+
Name: fmt.Sprintf("foo %d", rInt),
268+
ProjectsLimit: 0,
269+
Admin: false,
270+
CanCreateGroup: false,
271+
External: false,
272+
State: "deactivated",
273+
}),
274+
),
275+
},
276+
// Block the user from deactivate state
277+
{
278+
Config: testAccGitlabUserConfigBlocked(rInt),
279+
Check: resource.ComposeTestCheckFunc(
280+
testAccCheckGitlabUserExists("gitlab_user.foo", &user),
281+
testAccCheckGitlabUserAttributes(&user, &testAccGitlabUserExpectedAttributes{
282+
Email: fmt.Sprintf("listest%[email protected]", rInt),
283+
Username: fmt.Sprintf("listest%d", rInt),
284+
Name: fmt.Sprintf("foo %d", rInt),
285+
ProjectsLimit: 0,
286+
Admin: false,
287+
CanCreateGroup: false,
288+
External: false,
289+
State: "blocked",
290+
}),
291+
),
292+
},
293+
// Unblock the user
294+
{
295+
Config: testAccGitlabUserConfig(rInt),
296+
Check: resource.ComposeTestCheckFunc(
297+
testAccCheckGitlabUserExists("gitlab_user.foo", &user),
298+
testAccCheckGitlabUserAttributes(&user, &testAccGitlabUserExpectedAttributes{
299+
Email: fmt.Sprintf("listest%[email protected]", rInt),
300+
Username: fmt.Sprintf("listest%d", rInt),
301+
Name: fmt.Sprintf("foo %d", rInt),
302+
ProjectsLimit: 0,
303+
Admin: false,
304+
CanCreateGroup: false,
305+
External: false,
306+
State: "active",
307+
}),
308+
),
309+
},
208310
},
209311
})
210312
}
@@ -440,3 +542,19 @@ resource "gitlab_user" "foo" {
440542
}
441543
`, rInt, rInt, rInt)
442544
}
545+
546+
func testAccGitlabUserConfigDeactivated(rInt int) string {
547+
return fmt.Sprintf(`
548+
resource "gitlab_user" "foo" {
549+
name = "foo %d"
550+
username = "listest%d"
551+
password = "test%dtt"
552+
email = "listest%[email protected]"
553+
is_admin = false
554+
projects_limit = 0
555+
can_create_group = false
556+
is_external = false
557+
state = "deactivated"
558+
}
559+
`, rInt, rInt, rInt, rInt)
560+
}

0 commit comments

Comments
 (0)