Skip to content

Commit f586dc3

Browse files
authored
Merge pull request #380 from armsnyder/371-masked-validation
gitlab_project_variable: friendlier error when masked variable is invalid
2 parents de14c7d + 994a2b8 commit f586dc3

File tree

2 files changed

+116
-3
lines changed

2 files changed

+116
-3
lines changed

gitlab/resource_gitlab_project_variable.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package gitlab
22

33
import (
4+
"errors"
45
"log"
6+
"net/http"
7+
"strings"
58

69
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
710
gitlab "github.com/xanzy/go-gitlab"
@@ -82,7 +85,7 @@ func resourceGitlabProjectVariableCreate(d *schema.ResourceData, meta interface{
8285

8386
_, _, err := client.ProjectVariables.CreateVariable(project, &options)
8487
if err != nil {
85-
return err
88+
return augmentProjectVariableClientError(d, err)
8689
}
8790

8891
d.SetId(buildTwoPartID(&project, &key))
@@ -102,7 +105,7 @@ func resourceGitlabProjectVariableRead(d *schema.ResourceData, meta interface{})
102105

103106
v, _, err := client.ProjectVariables.GetVariable(project, key)
104107
if err != nil {
105-
return err
108+
return augmentProjectVariableClientError(d, err)
106109
}
107110

108111
d.Set("key", v.Key)
@@ -140,7 +143,7 @@ func resourceGitlabProjectVariableUpdate(d *schema.ResourceData, meta interface{
140143

141144
_, _, err := client.ProjectVariables.UpdateVariable(project, key, options)
142145
if err != nil {
143-
return err
146+
return augmentProjectVariableClientError(d, err)
144147
}
145148

146149
return resourceGitlabProjectVariableRead(d, meta)
@@ -153,5 +156,24 @@ func resourceGitlabProjectVariableDelete(d *schema.ResourceData, meta interface{
153156
log.Printf("[DEBUG] Delete gitlab project variable %s/%s", project, key)
154157

155158
_, err := client.ProjectVariables.RemoveVariable(project, key)
159+
return augmentProjectVariableClientError(d, err)
160+
}
161+
162+
func augmentProjectVariableClientError(d *schema.ResourceData, err error) error {
163+
// Masked values will commonly error due to their strict requirements, and the error message from the GitLab API is not very informative,
164+
// so we return a custom error message in this case.
165+
if d.Get("masked").(bool) && isInvalidValueError(err) {
166+
log.Printf("[ERROR] %v", err)
167+
return errors.New("Invalid value for a masked variable. Check the masked variable requirements: https://docs.gitlab.com/ee/ci/variables/#masked-variable-requirements")
168+
}
169+
156170
return err
157171
}
172+
173+
func isInvalidValueError(err error) bool {
174+
var httpErr *gitlab.ErrorResponse
175+
return errors.As(err, &httpErr) &&
176+
httpErr.Response.StatusCode == http.StatusBadRequest &&
177+
strings.Contains(httpErr.Message, "value") &&
178+
strings.Contains(httpErr.Message, "invalid")
179+
}

gitlab/resource_gitlab_project_variable_test.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package gitlab
22

33
import (
44
"fmt"
5+
"regexp"
56
"testing"
67

78
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
@@ -54,6 +55,46 @@ func TestAccGitlabProjectVariable_basic(t *testing.T) {
5455
}),
5556
),
5657
},
58+
// Update the project variable to enable "masked" for a value that does not meet masking requirements, and expect an error with no state change.
59+
// ref: https://docs.gitlab.com/ce/ci/variables/README.html#masked-variable-requirements
60+
{
61+
Config: testAccGitlabProjectVariableUpdateConfigMaskedBad(rString),
62+
Check: resource.ComposeTestCheckFunc(
63+
testAccCheckGitlabProjectVariableExists("gitlab_project_variable.foo", &projectVariable),
64+
testAccCheckGitlabProjectVariableAttributes(&projectVariable, &testAccGitlabProjectVariableExpectedAttributes{
65+
Key: fmt.Sprintf("key_%s", rString),
66+
Value: fmt.Sprintf("value-%s", rString),
67+
}),
68+
),
69+
ExpectError: regexp.MustCompile(regexp.QuoteMeta(
70+
"Invalid value for a masked variable. Check the masked variable requirements: https://docs.gitlab.com/ee/ci/variables/#masked-variable-requirements",
71+
)),
72+
},
73+
// Update the project variable to to enable "masked" and meet masking requirements
74+
// ref: https://docs.gitlab.com/ce/ci/variables/README.html#masked-variable-requirements
75+
{
76+
Config: testAccGitlabProjectVariableUpdateConfigMaskedGood(rString),
77+
Check: resource.ComposeTestCheckFunc(
78+
testAccCheckGitlabProjectVariableExists("gitlab_project_variable.foo", &projectVariable),
79+
testAccCheckGitlabProjectVariableAttributes(&projectVariable, &testAccGitlabProjectVariableExpectedAttributes{
80+
Key: fmt.Sprintf("key_%s", rString),
81+
Value: fmt.Sprintf("value-%s", rString),
82+
Masked: true,
83+
}),
84+
),
85+
},
86+
// Update the project variable to toggle the options back
87+
{
88+
Config: testAccGitlabProjectVariableConfig(rString),
89+
Check: resource.ComposeTestCheckFunc(
90+
testAccCheckGitlabProjectVariableExists("gitlab_project_variable.foo", &projectVariable),
91+
testAccCheckGitlabProjectVariableAttributes(&projectVariable, &testAccGitlabProjectVariableExpectedAttributes{
92+
Key: fmt.Sprintf("key_%s", rString),
93+
Value: fmt.Sprintf("value-%s", rString),
94+
Protected: false,
95+
}),
96+
),
97+
},
5798
},
5899
})
59100
}
@@ -88,6 +129,7 @@ type testAccGitlabProjectVariableExpectedAttributes struct {
88129
Key string
89130
Value string
90131
Protected bool
132+
Masked bool
91133
}
92134

93135
func testAccCheckGitlabProjectVariableAttributes(variable *gitlab.ProjectVariable, want *testAccGitlabProjectVariableExpectedAttributes) resource.TestCheckFunc {
@@ -104,6 +146,10 @@ func testAccCheckGitlabProjectVariableAttributes(variable *gitlab.ProjectVariabl
104146
return fmt.Errorf("got protected %t; want %t", variable.Protected, want.Protected)
105147
}
106148

149+
if variable.Masked != want.Masked {
150+
return fmt.Errorf("got masked %t; want %t", variable.Masked, want.Masked)
151+
}
152+
107153
return nil
108154
}
109155
}
@@ -171,3 +217,48 @@ resource "gitlab_project_variable" "foo" {
171217
}
172218
`, rString, rString, rString)
173219
}
220+
221+
func testAccGitlabProjectVariableUpdateConfigMaskedBad(rString string) string {
222+
return fmt.Sprintf(`
223+
resource "gitlab_project" "foo" {
224+
name = "foo-%s"
225+
description = "Terraform acceptance tests"
226+
227+
# So that acceptance tests can be run in a gitlab organization
228+
# with no billing
229+
visibility_level = "public"
230+
}
231+
232+
resource "gitlab_project_variable" "foo" {
233+
project = "${gitlab_project.foo.id}"
234+
key = "key_%s"
235+
value = <<EOF
236+
value-%s"
237+
i am multiline
238+
EOF
239+
variable_type = "env_var"
240+
masked = true
241+
}
242+
`, rString, rString, rString)
243+
}
244+
245+
func testAccGitlabProjectVariableUpdateConfigMaskedGood(rString string) string {
246+
return fmt.Sprintf(`
247+
resource "gitlab_project" "foo" {
248+
name = "foo-%s"
249+
description = "Terraform acceptance tests"
250+
251+
# So that acceptance tests can be run in a gitlab organization
252+
# with no billing
253+
visibility_level = "public"
254+
}
255+
256+
resource "gitlab_project_variable" "foo" {
257+
project = "${gitlab_project.foo.id}"
258+
key = "key_%s"
259+
value = "value-%s"
260+
variable_type = "env_var"
261+
masked = true
262+
}
263+
`, rString, rString, rString)
264+
}

0 commit comments

Comments
 (0)