Skip to content

Commit

Permalink
Merge pull request #20 from raydouglass/list-excludes
Browse files Browse the repository at this point in the history
Allow for lists as values in excludes mappings
  • Loading branch information
sue445 authored Nov 20, 2020
2 parents 8f0fcd2 + c077263 commit ca25fe8
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 10 deletions.
40 changes: 38 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,16 @@ Generate yaml based matrix and run job :muscle:
## Detail
### Excluding logic
Excluding pattern may be specified with `List` of `Map` (e.g. `List<Map<String, String>>`)
Excluding pattern may be specified with `List` of `Map` (e.g. `List<Map<String, [String or List]>>`)

Elements in the `Map` may be a List to exclude multiple items for one key
```yaml
# axis.yml
exclude:
- RUBY_VERSION: 2.1.8
- RUBY_VERSION: 2.3.0
DATABASE: oracle
```

When specified 2 axes

![axis](doc/axis.png)
Expand All @@ -86,3 +86,39 @@ This results in a 3x3 build matrix.
* `RUBY_VERSION` value `2.1.8` and `DATABASE` value `oracle` is excluded
* When specified `RUBY_VERSION` value `2.3.0` and `DATABASE` value `oracle`, 1 result is excluded
* `RUBY_VERSION` value `2.3.0` and `DATABASE` value `oracle` is excluded

#### Another example
```yaml
# axis2.yml
exclude:
- RUBY_VERSION: 2.1.8
- RUBY_VERSION: 2.3.0
DATABASE:
- oracle
- mysql
```
* When specified `RUBY_VERSION` value `2.1.8`, 3 results are excluded
* `RUBY_VERSION` value `2.1.8` and `DATABASE` value `mysql` is excluded
* `RUBY_VERSION` value `2.1.8` and `DATABASE` value `postgres` is excluded
* `RUBY_VERSION` value `2.1.8` and `DATABASE` value `oracle` is excluded
* When specified `RUBY_VERSION` value `2.3.0`, 2 results are excluded
* `RUBY_VERSION` value `2.3.0` and `DATABASE` value `oracle` is excluded
* `RUBY_VERSION` value `2.3.0` and `DATABASE` value `mysql` is excluded

#### Final example
Using multiple lists will exclude the cartesian product of those lists.
```yaml
# axis3.yml
exclude:
- RUBY_VERSION:
- 2.1.8
- 2.3.0
DATABASE:
- oracle
- mysql
```
* 4 results are excluded
* `RUBY_VERSION` value `2.1.8` and `DATABASE` value `mysql` is excluded
* `RUBY_VERSION` value `2.1.8` and `DATABASE` value `oracle` is excluded
* `RUBY_VERSION` value `2.3.0` and `DATABASE` value `oracle` is excluded
* `RUBY_VERSION` value `2.3.0` and `DATABASE` value `mysql` is excluded
11 changes: 9 additions & 2 deletions src/main/groovy/org/jenkinsci/plugins/yamlaxis/YamlLoader.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,21 @@ abstract class YamlLoader {
* @param key
* @return if key is not found, return null
*/
List<Map<String, String>> loadMaps(String key){
List<Map<String, ?>> loadMaps(String key){
Map content = getContent()
def values = content.get(key)
if(values == null){
return null
}
values.collect {
it.collectEntries { k, v -> [k, v.toString()] }
it.collectEntries { k, v ->
if(v instanceof List){
[k, v.collect { it.toString() }]
}else{
[k, v.toString()]
}
}

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,53 @@ class YamlMatrixExecutionStrategy extends BaseMES {
BuildUtils.log(execution, "[WARN] NotFound excludeKey ${excludeKey}")
return []
}
values.collect { new Combination(it) }
collectExcludeCombinations(values)

} catch (IOException e) {
BuildUtils.log(execution, "[WARN] Can not read yamlFile: ${yamlFile}", e)
[]
}
}

public static List<Combination> collectExcludeCombinations(List<Map<String, ?>> excludes) {
List<Map<String, String>> result = []
for (value in excludes) {
List<Map<String, String>> combos = []
boolean isList = false
for (Map.Entry<String, ?> entry in value) {
if (entry.value instanceof List) {
isList = true
List<Map<String, String>> newCombos = []
for (def v in entry.value) {
if (combos) {
for (def c in combos) {
Map<String, String> clone = new HashMap<>(c)
clone.put(entry.key, v)
newCombos.add(clone)
}
} else {
newCombos.add([(entry.key): v])
}
}
combos = newCombos
}
}
if (isList) {
for (Map.Entry<String, ?> entry in value) {
if (entry.value instanceof String) {
for (def c in combos) {
c.put(entry.key, entry.value)
}
}
}
} else {
combos.add(value)
}
result.addAll(combos)
}
result.collect { new Combination(it) }
}

private YamlLoader getYamlLoader(MatrixBuild.MatrixBuildExecution execution){
switch(yamlType){
case YamlFileLoader.RADIO_VALUE:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class YamlMatrixExecutionStrategySpec extends Specification {
def "run"() {
setup:
def matrixProject = configure()
List<Combination> excludeCombinations = excludes.collect { new Combination(it) }
List<Combination> excludeCombinations = YamlMatrixExecutionStrategy.collectExcludeCombinations(excludes)
matrixProject.executionStrategy = new YamlMatrixExecutionStrategy(excludeCombinations)
def build = matrixProject.scheduleBuild2(0).get()

Expand All @@ -40,9 +40,16 @@ class YamlMatrixExecutionStrategySpec extends Specification {
build.runs.size() == runsCount

where:
excludes || runsCount
[] || 9
[[axis1: "c", axis2: "z"]] || 8
[[axis1: "c"]] || 6
excludes || runsCount
[] || 9
[[axis1: "c", axis2: "z"]] || 8
[[axis1: "c", axis2: ["z"]]] || 8
[[axis1: ["c"], axis2: "z"]] || 8
[[axis1: ["c"], axis2: ["z"]]] || 8
[[axis1: "c"]] || 6
[[axis1: ["b", "c"]]] || 3
[[axis1: "b"], [axis1: "c"]] || 3
[[axis1: "b", axis2: ["x", "y"]]] || 7
[[axis1: ["a", "b"], axis2: ["x", "y"]]] || 5
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,26 @@ exclude:
"exclude" || [[a: "1", b: "2"], [c: "3"]]
"not_found" || null
}

def "loadValuesList"(){
setup:
String yamlText = """
exclude:
- a: 1
b:
- 2
- 3
- c: 4
"""

def loader = new YamlTextLoader(yamlText: yamlText)

expect:
loader.loadMaps(key) == expected

where:
key || expected
"exclude" || [[a: "1", b: ["2", "3"]], [c: "4"]]
"not_found" || null
}
}

0 comments on commit ca25fe8

Please sign in to comment.