support the same selector repeated
This commit is contained in:
		
							parent
							
								
									79c7d1501a
								
							
						
					
					
						commit
						789362dfd4
					
				|  | @ -15,14 +15,16 @@ type ReleaseFilter interface { | ||||||
| // LabelFilter matches a release with the given positive lables. Negative labels
 | // LabelFilter matches a release with the given positive lables. Negative labels
 | ||||||
| // invert the match for cases such as tier!=backend
 | // invert the match for cases such as tier!=backend
 | ||||||
| type LabelFilter struct { | type LabelFilter struct { | ||||||
| 	positiveLabels map[string]string | 	positiveLabels [][]string | ||||||
| 	negativeLabels map[string]string | 	negativeLabels [][]string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Match will match a release that has the same labels as the filter
 | // Match will match a release that has the same labels as the filter
 | ||||||
| func (l LabelFilter) Match(r ReleaseSpec) bool { | func (l LabelFilter) Match(r ReleaseSpec) bool { | ||||||
| 	if len(l.positiveLabels) > 0 { | 	if len(l.positiveLabels) > 0 { | ||||||
| 		for k, v := range l.positiveLabels { | 		for _, element := range l.positiveLabels { | ||||||
|  | 			k := element[0] | ||||||
|  | 			v := element[1] | ||||||
| 			if rVal, ok := r.Labels[k]; !ok { | 			if rVal, ok := r.Labels[k]; !ok { | ||||||
| 				return false | 				return false | ||||||
| 			} else if rVal != v { | 			} else if rVal != v { | ||||||
|  | @ -30,8 +32,11 @@ func (l LabelFilter) Match(r ReleaseSpec) bool { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	if len(l.negativeLabels) > 0 { | 	if len(l.negativeLabels) > 0 { | ||||||
| 		for k, v := range l.negativeLabels { | 		for _, element := range l.negativeLabels { | ||||||
|  | 			k := element[0] | ||||||
|  | 			v := element[1] | ||||||
| 			if rVal, ok := r.Labels[k]; !ok { | 			if rVal, ok := r.Labels[k]; !ok { | ||||||
| 				return true | 				return true | ||||||
| 			} else if rVal == v { | 			} else if rVal == v { | ||||||
|  | @ -45,17 +50,17 @@ func (l LabelFilter) Match(r ReleaseSpec) bool { | ||||||
| // ParseLabels takes a label in the form foo=bar,baz!=bat and returns a LabelFilter that will match the labels
 | // ParseLabels takes a label in the form foo=bar,baz!=bat and returns a LabelFilter that will match the labels
 | ||||||
| func ParseLabels(l string) (LabelFilter, error) { | func ParseLabels(l string) (LabelFilter, error) { | ||||||
| 	lf := LabelFilter{} | 	lf := LabelFilter{} | ||||||
| 	lf.positiveLabels = map[string]string{} | 	lf.positiveLabels = [][]string{} | ||||||
| 	lf.negativeLabels = map[string]string{} | 	lf.negativeLabels = [][]string{} | ||||||
| 	var err error | 	var err error | ||||||
| 	labels := strings.Split(l, ",") | 	labels := strings.Split(l, ",") | ||||||
| 	for _, label := range labels { | 	for _, label := range labels { | ||||||
| 		if match, _ := regexp.MatchString("^[a-zA-Z0-9_-]+!=[a-zA-Z0-9_-]+$", label); match == true { // k!=v case
 | 		if match, _ := regexp.MatchString("^[a-zA-Z0-9_-]+!=[a-zA-Z0-9_-]+$", label); match == true { // k!=v case
 | ||||||
| 			kv := strings.Split(label, "!=") | 			kv := strings.Split(label, "!=") | ||||||
| 			lf.negativeLabels[kv[0]] = kv[1] | 			lf.negativeLabels = append(lf.negativeLabels, kv) | ||||||
| 		} else if match, _ := regexp.MatchString("^[a-zA-Z0-9_-]+=[a-zA-Z0-9_-]+$", label); match == true { // k=v case
 | 		} else if match, _ := regexp.MatchString("^[a-zA-Z0-9_-]+=[a-zA-Z0-9_-]+$", label); match == true { // k=v case
 | ||||||
| 			kv := strings.Split(label, "=") | 			kv := strings.Split(label, "=") | ||||||
| 			lf.positiveLabels[kv[0]] = kv[1] | 			lf.positiveLabels = append(lf.positiveLabels, kv) | ||||||
| 		} else { // malformed case
 | 		} else { // malformed case
 | ||||||
| 			err = fmt.Errorf("Malformed label: %s. Expected label in form k=v or k!=v", label) | 			err = fmt.Errorf("Malformed label: %s. Expected label in form k=v or k!=v", label) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -87,13 +87,13 @@ func TestReadFromYaml_FilterReleasesOnLabels(t *testing.T) { | ||||||
| 		filter  LabelFilter | 		filter  LabelFilter | ||||||
| 		results []bool | 		results []bool | ||||||
| 	}{ | 	}{ | ||||||
| 		{LabelFilter{positiveLabels: map[string]string{"tier": "frontend"}}, | 		{LabelFilter{positiveLabels: [][]string{[]string{"tier", "frontend"}}}, | ||||||
| 			[]bool{true, true, false}}, | 			[]bool{true, true, false}}, | ||||||
| 		{LabelFilter{positiveLabels: map[string]string{"tier": "frontend", "foo": "bar"}}, | 		{LabelFilter{positiveLabels: [][]string{[]string{"tier", "frontend"}, []string{"foo", "bar"}}}, | ||||||
| 			[]bool{true, false, false}}, | 			[]bool{true, false, false}}, | ||||||
| 		{LabelFilter{negativeLabels: map[string]string{"tier": "frontend"}}, | 		{LabelFilter{negativeLabels: [][]string{[]string{"tier", "frontend"}}}, | ||||||
| 			[]bool{false, false, true}}, | 			[]bool{false, false, true}}, | ||||||
| 		{LabelFilter{positiveLabels: map[string]string{"tier": "frontend"}, negativeLabels: map[string]string{"foo": "bar"}}, | 		{LabelFilter{positiveLabels: [][]string{[]string{"tier", "frontend"}}, negativeLabels: [][]string{[]string{"foo", "bar"}}}, | ||||||
| 			[]bool{false, true, false}}, | 			[]bool{false, true, false}}, | ||||||
| 	} | 	} | ||||||
| 	state, err := readFromYaml(yamlContent, yamlFile) | 	state, err := readFromYaml(yamlContent, yamlFile) | ||||||
|  | @ -109,18 +109,57 @@ func TestReadFromYaml_FilterReleasesOnLabels(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestReadFromYaml_FilterNegatives(t *testing.T) { | ||||||
|  | 	yamlFile := "example/path/to/yaml/file" | ||||||
|  | 	yamlContent := []byte(`releases: | ||||||
|  | - name: myrelease1 | ||||||
|  |   chart: mychart1 | ||||||
|  |   labels: | ||||||
|  |     stage: pre | ||||||
|  |     foo: bar | ||||||
|  | - name: myrelease2 | ||||||
|  |   chart: mychart2 | ||||||
|  |   labels: | ||||||
|  |     stage: post | ||||||
|  | - name: myrelease3 | ||||||
|  |   chart: mychart3 | ||||||
|  | `) | ||||||
|  | 	cases := []struct { | ||||||
|  | 		filter  LabelFilter | ||||||
|  | 		results []bool | ||||||
|  | 	}{ | ||||||
|  | 		{LabelFilter{positiveLabels: [][]string{[]string{"stage", "pre"}}}, | ||||||
|  | 			[]bool{true, false, false}}, | ||||||
|  | 		{LabelFilter{positiveLabels: [][]string{[]string{"stage", "post"}}}, | ||||||
|  | 			[]bool{false, true, false}}, | ||||||
|  | 		{LabelFilter{negativeLabels: [][]string{[]string{"stage", "pre"}, []string{"stage", "post"}}}, | ||||||
|  | 			[]bool{false, false, true}}, | ||||||
|  | 	} | ||||||
|  | 	state, err := readFromYaml(yamlContent, yamlFile) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("unexpected error: %v", err) | ||||||
|  | 	} | ||||||
|  | 	for idx, c := range cases { | ||||||
|  | 		for idx2, expected := range c.results { | ||||||
|  | 			if f := c.filter.Match(state.Releases[idx2]); f != expected { | ||||||
|  | 				t.Errorf("[case: %d][outcome: %d] Unexpected outcome wanted %t, got %t", idx, idx2, expected, f) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func TestLabelParsing(t *testing.T) { | func TestLabelParsing(t *testing.T) { | ||||||
| 	cases := []struct { | 	cases := []struct { | ||||||
| 		labelString    string | 		labelString    string | ||||||
| 		expectedFilter LabelFilter | 		expectedFilter LabelFilter | ||||||
| 		errorExected   bool | 		errorExected   bool | ||||||
| 	}{ | 	}{ | ||||||
| 		{"foo=bar", LabelFilter{positiveLabels: map[string]string{"foo": "bar"}, negativeLabels: map[string]string{}}, false}, | 		{"foo=bar", LabelFilter{positiveLabels: [][]string{[]string{"foo", "bar"}}, negativeLabels: [][]string{}}, false}, | ||||||
| 		{"foo!=bar", LabelFilter{positiveLabels: map[string]string{}, negativeLabels: map[string]string{"foo": "bar"}}, false}, | 		{"foo!=bar", LabelFilter{positiveLabels: [][]string{}, negativeLabels: [][]string{[]string{"foo", "bar"}}}, false}, | ||||||
| 		{"foo!=bar,baz=bat", LabelFilter{positiveLabels: map[string]string{"baz": "bat"}, negativeLabels: map[string]string{"foo": "bar"}}, false}, | 		{"foo!=bar,baz=bat", LabelFilter{positiveLabels: [][]string{[]string{"baz", "bat"}}, negativeLabels: [][]string{[]string{"foo", "bar"}}}, false}, | ||||||
| 		{"foo", LabelFilter{positiveLabels: map[string]string{}, negativeLabels: map[string]string{}}, true}, | 		{"foo", LabelFilter{positiveLabels: [][]string{}, negativeLabels: [][]string{}}, true}, | ||||||
| 		{"foo!=bar=baz", LabelFilter{positiveLabels: map[string]string{}, negativeLabels: map[string]string{}}, true}, | 		{"foo!=bar=baz", LabelFilter{positiveLabels: [][]string{}, negativeLabels: [][]string{}}, true}, | ||||||
| 		{"=bar", LabelFilter{positiveLabels: map[string]string{}, negativeLabels: map[string]string{}}, true}, | 		{"=bar", LabelFilter{positiveLabels: [][]string{}, negativeLabels: [][]string{}}, true}, | ||||||
| 	} | 	} | ||||||
| 	for idx, c := range cases { | 	for idx, c := range cases { | ||||||
| 		filter, err := ParseLabels(c.labelString) | 		filter, err := ParseLabels(c.labelString) | ||||||
|  | @ -129,7 +168,7 @@ func TestLabelParsing(t *testing.T) { | ||||||
| 		} else if err == nil && c.errorExected { | 		} else if err == nil && c.errorExected { | ||||||
| 			t.Errorf("[%d] Expected %s to result in an error but got none", idx, c.labelString) | 			t.Errorf("[%d] Expected %s to result in an error but got none", idx, c.labelString) | ||||||
| 		} else if !reflect.DeepEqual(filter, c.expectedFilter) { | 		} else if !reflect.DeepEqual(filter, c.expectedFilter) { | ||||||
| 			t.Errorf("[%d] parsed label did not result in expected filter: %v", idx, filter) | 			t.Errorf("[%d] parsed label did not result in expected filter: %v, expected: %v", idx, filter, c.expectedFilter) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue