-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support non-string template parameter substitution #11421
Conversation
94211e7
to
09a8a90
Compare
@smarterclayton ptal. |
@csrwng ptal also |
@openshift/api-review needs review. |
5654894
to
3ef73bd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really minor nits, otherwise LGTM
@@ -126,15 +130,32 @@ func GetParameterByName(t *api.Template, name string) *api.Parameter { | |||
|
|||
// EvaluateParameterSubstitution replaces escaped parameters in a string with values from the | |||
// provided map. | |||
func (p *Processor) EvaluateParameterSubstitution(params map[string]api.Parameter, in string) string { | |||
for _, match := range parameterExp.FindAllStringSubmatch(in, -1) { | |||
func (p *Processor) EvaluateParameterSubstitution(params map[string]api.Parameter, in string) (string, bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should mention in the comment what the bool is for
if len(match) > 1 { | ||
if paramValue, found := params[match[1]]; found { | ||
in = strings.Replace(in, match[0], paramValue.Value, 1) | ||
return in, false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
really minor nit ... you should name your result variable differently (assign result := in at the beginning of the function). Seems strange returning in
.
3ef73bd
to
0a01a54
Compare
nits addressed |
// match ${KEY}, KEY will be grouped | ||
var stringParameterExp = regexp.MustCompile(`\$\{([a-zA-Z0-9\_]+?)\}`) | ||
|
||
// match ${{KEY}} exact match only, KEY will be grouped |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is neat. I like it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can thank @smarterclayton. I wanted to do much crazier things w/ substitution :)
} else { | ||
b = []byte(fmt.Sprintf("{\"k\":%s}", s)) | ||
} | ||
var data map[string]interface{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var data interface{}
You shouldn't need the "as string" syntax.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
without "asString" how does the encoder differentiate between "true" (the string) and true (the boolean value)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and i don't understand the var data interface{} suggestion. i definitely don't know the json mechanisms as well as you, but i thought i needed to decode into a map[string]interface in order to get the library to decode the arbitrary json string into a proper go type. If i just decode a string (not part of a json map), it will always get turned into a string, not a specific data type.
that is, json.Unmarshal("true",&data) is never going to give me the boolean value that i need in some cases (and in other cases i need it to give me the string type)
if i'm still wrong let's chat tomorrow.
"key2": "$${VALUE}", | ||
"s1_s1": "${STRING_1}_${STRING_1}", | ||
"s1_s2": "${STRING_1}_${STRING_2}", | ||
"i1": "${{INT_1}}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add more tests that verify that this syntax in combination with before and after stays a string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or return an error when you get a template with "${{INT_1}}bar" (didn't we say we would validate for that)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can't return an error for that because it was valid syntax before this change, so we need to continue to tolerate it w/o throwing an error.
but i will add a test to ensure we don't mutate it.
var stringParameterExp = regexp.MustCompile(`\$\{([a-zA-Z0-9\_]+?)\}`) | ||
|
||
// match ${{KEY}} exact match only, KEY will be grouped | ||
var nonStringParameterExp = regexp.MustCompile(`^\$\{\{([a-zA-Z0-9\_]+)\}\}$`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to decide whether to error on invalid usage of this, and if we do then the regex needs to be looser.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As is "${{FOO }}" is ignored which is very weird (ignoring seems wrong, erroring seems probably right, unless we think we can't safely error because of backcompat)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think we can't safely error because of backward compatibility. Someone could legitimately have "${{BLAH}}" in a template somewhere. (or "${{BLA H}}" or "B${{LAH}}" or any of the other permutations the regex currently ignores). (Arguably even introducing the ${{KEY}} syntax could break existing templates that for some reason contained a value ${{KEY}} reference in a string field, but presumably we have to accept that. So perhaps you want to make the argument that since we're already introducing a (slightly) breaking change, we can expand the number of scenarios under which people will be broken?)
That said, you'll ultimately get an error anyway if you were attempting parameter substitution into a non-string field and the substitution didn't happen because you didn't provide a valid parameter name, or because you included a prefix/suffix on the ${{KEY}}} parameter reference.
that is, you'll ultimately get an error because the resulting api object won't be valid (will contain a string value for an int/boolean/float field)
Only remaining question is error and validation. Rest is fine. |
0a01a54
to
6b98e30
Compare
@smarterclayton added requested additional tests but will need to discuss
|
6b98e30
to
b4be712
Compare
case reflect.String: | ||
if !v.CanSet() { | ||
glog.Infof("Unable to set String value '%v'", v) | ||
return | ||
return fmt.Errorf("Unable to set String value '%v'", v) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: remember all your errors need to be lowercase first char
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may actually want to be able to walk everything and get errors on specific fields. I.e. if you have 3 failures we want to report them all, not just the first one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will change the error case.
as for multiple errors, that sort of thing hasn't been a concern users have raised so far w/ the existing template processing error behavior and i'd prefer to entertain that as a follow on at this point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
error case updated
// which is an error when decoding in json(only "true", "false", and numeric | ||
// values can be unquoted), so try wrapping the value in quotes so it will be | ||
// properly converted to a string type during decoding. | ||
b = []byte(fmt.Sprintf("\"%s\"", s)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just call val = reflect.ValueOf(s)
here. If it's a string, it's a string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
b4be712
to
d10943b
Compare
@smarterclayton ok i think this is ready for a final review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More tests
"key2": "$${VALUE}", | ||
"s1_s1": "${STRING_1}_${STRING_1}", | ||
"s1_s2": "${STRING_1}_${STRING_2}", | ||
"i1": "${{INT_1}}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create test conditions for the "error" case is described above. Also bad json substitution error case. I'd like a test that covers all the "broken" cases as well as the working cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create test conditions for the "error" case is described above
not sure which case you're referring to, but there are three tests for "invalid" ${{KEY}} substitutions ("a${{KEY}}", "${{KEY}}a", and "${{INVALID_PARAMETER}}", all of which ensure that the value isn't touched in those cases (backwards compatible behavior).
Also bad json substitution error case
There is no "bad json substitution" scenario. if you use the ${{KEY}} syntax w/ a random string parameter value(non-json value), you end up with a quoted string because we fail to decode it and then use it as a direct string value instead. that's tested by the "quoted_string" key test. (ensures that if you use the ${{KEY}} syntax but the parameter value is not an int/bool, you end up with a quoted string containing the parameter value)
I don't think there's any case where we would explicitly error based on the substitution logic, we will either: do a string substitution instead of an int/boolean substitution, or we will do no substitution (leaving a string value with a ${{FOO}} reference embedded).
Those things might result in an invalid api object, but we've never done checking for that sort of thing, the template processing is api object agnostic.
Guessing there is still a scenario you're thinking of that i'm missing but i don't see it at the moment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added one more test for a "${{INVALID PARAMETER}}" reference (should be untouched)
d10943b
to
11317b8
Compare
flake #11094 |
I think we all like the format. Marked API approved. |
11317b8
to
b96243f
Compare
@smarterclayton final set of tests added. this does work w/ syntaxes like: parameter reference:
json parameter value:
results in:
|
flake #11016 |
b96243f
to
23eb8fb
Compare
Evaluated for origin test up to 23eb8fb |
continuous-integration/openshift-jenkins/test SUCCESS (https://ci.openshift.redhat.com/jenkins/job/test_pr_origin/10582/) (Base Commit: f1d0dd2) |
@pweil- or @smarterclayton are you signing off on this going in despite being past dcut? |
Lgtm once you go green On Oct 24, 2016, at 5:29 PM, OpenShift Bot [email protected] wrote: continuous-integration/openshift-jenkins/test SUCCESS ( — |
extended test passed despite github not reflecting that and travis is doing the govet shadow spurious failure but i've kicked it for a rerun. waiting for QE to agree to test it anyway before i merge. |
I'm looking for the test to actually demonstrate the complex json On Oct 23, 2016, at 2:59 AM, Ben Parees [email protected] wrote: @bparees commented on this pull request.In pkg/template/template_test.go
+func TestProcessValue(t *testing.T) {
Create test conditions for the "error" case is described above not sure which case you're referring to, but there are three tests for Also bad json substitution error case There is no "bad json substitution" scenario. if you use the ${{KEY}} I don't think there's any case where we would explicitly error based on the Those things might result in an invalid api object, but we've never done Guessing there is still a scenario you're thinking of that i'm missing but — |
[textextended][extended:core(openshift pipeline build Manual deploy)] |
[merge] |
Evaluated for origin merge up to 23eb8fb |
continuous-integration/openshift-jenkins/merge SUCCESS (https://ci.openshift.redhat.com/jenkins/job/test_pr_origin/10657/) (Base Commit: ca101d7) (Image: devenv-rhel7_5245) |
fixes #3946
fixes bug 1383812