Skip to content

Commit

Permalink
fix(travis): Correctly parse global_env from Travis v3 API (#504)
Browse files Browse the repository at this point in the history
When the `config` section is returned as part of a *build* (which is unsupported in the Travis v3 API), `global_env` is a list of Strings. When it is returned as part of a *job*, `global_env` is instead a space separated String. And since env variable values can also contain spaces and equal signs, I had to create a little regex parser thingy.
This also fixes an issue in Deck where you can't add parameters to a Travis stage if `.travis.yml` contains anything in the `env.global` section.
  • Loading branch information
jervi authored and emjburns committed Sep 13, 2019
1 parent 1f60f14 commit 093f121
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,30 @@

package com.netflix.spinnaker.igor.travis.client.model.v3;

import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.netflix.spinnaker.igor.build.model.GenericParameterDefinition;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.simpleframework.xml.Default;

@Default
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@Slf4j
public class Config {
@JsonProperty("global_env")
private List<Object> globalEnv;

@JsonProperty("merge_mode")
Expand Down Expand Up @@ -75,12 +82,34 @@ public List<GenericParameterDefinition> getParameterDefinitionList() {
.collect(Collectors.toList());
}

@JsonGetter("global_env")
public List<Object> getGlobalEnv() {
return globalEnv;
}

public void setGlobalEnv(List<Object> globalEnv) {
this.globalEnv = globalEnv;
@JsonSetter("global_env")
@SuppressWarnings("unchecked")
public void setGlobalEnv(Object globalEnv) {
if (globalEnv instanceof String) {
// Matches space separated KEY=VALUE pairs. See ConfigSpec for matching examples
Pattern pattern = Pattern.compile("(\\S*?)=(?>(?>[\"'])(.*?)(?>[\"'])|(\\S*))");
Matcher matcher = pattern.matcher((String) globalEnv);
List<String> env = new ArrayList<>();
while (matcher.find()) {
String key = matcher.group(1);
String value = matcher.group(2);
if (StringUtils.isBlank(value)) {
value = matcher.group(3);
}
value = StringUtils.trimToEmpty(value);
env.add(key + "=" + value);
}
this.globalEnv = new ArrayList<>(env);
} else if (globalEnv instanceof List) {
this.globalEnv = (List) globalEnv;
} else {
log.warn("Unknown type for 'global_env', ignoring: {}", globalEnv);
}
}

public String getMergeMode() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,130 @@ class TravisClientSpec extends Specification {
}
def "should parse v3 config section correctly"() {
given:
setResponse '''{
"@type": "builds",
"@href": "/api/repo/my-org%2Fmy-project/builds?limit=1&include=job.config",
"@representation": "standard",
"@pagination": {
"limit": 1,
"offset": 0,
"count": 1213,
"is_first": true,
"is_last": false,
"next": {
"@href": "/api/repo/my-org%2Fmy-project/builds?include=job.config&limit=1&offset=1",
"offset": 1,
"limit": 1
},
"prev": null,
"first": {
"@href": "/api/repo/my-org%2Fmy-project/builds?limit=1&include=job.config",
"offset": 0,
"limit": 1
},
"last": {
"@href": "/api/repo/my-org%2Fmy-project/builds?include=job.config&limit=1&offset=1212",
"offset": 1212,
"limit": 1
}
},
"builds": [
{
"@type": "build",
"@href": "/api/build/8078881",
"@representation": "standard",
"@permissions": {
"read": true,
"cancel": true,
"restart": true
},
"id": 8078881,
"number": "1213",
"state": "errored",
"duration": 19,
"event_type": "cron",
"previous_state": "failed",
"pull_request_title": null,
"pull_request_number": null,
"started_at": "2019-09-04T10:47:53Z",
"finished_at": "2019-09-04T10:48:12Z",
"repository": {
"@type": "repository",
"@href": "/api/repo/10094",
"@representation": "minimal",
"id": 10094,
"name": "my-project",
"slug": "my-org/my-project"
},
"branch": {
"@type": "branch",
"@href": "/api/repo/10094/branch/master",
"@representation": "minimal",
"name": "master"
},
"tag": null,
"commit": {
"@type": "commit",
"@representation": "minimal",
"id": 4571457,
"sha": "8af6ccfec7ea3cac6c3e01751186bc9ca5b6062e",
"ref": null,
"message": "Release 0.1.28",
"compare_url": "https://github.acme.com/my-org/my-project/compare/7a7214f554e2b8e313354af08c1010ad90f1e612...8af6ccfec7ea3cac6c3e01751186bc9ca5b6062e",
"committed_at": "2019-04-24T21:54:13Z"
},
"jobs": [
{
"@type": "job",
"@href": "/api/job/8078882",
"@representation": "minimal",
"id": 8078882,
"config": {
"language": "python",
"cache": "pip",
"install": "script/bootstrap",
"script": "script/cibuild",
"after_script": "script/cleanup",
".result": "configured",
"global_env": "REGION=eu-west-1 STACK_NAME=testing A_USER=user@schibsted.com A_PWD=[secure] KEY_ID=\\"MY_KEY\\" A_SECRET=[secure] ROLE='arn:aws:iam::0123456789:role/myRole'",
"os": "linux",
"group": "stable",
"dist": "trusty",
"addons": {}
}
}
],
"stages": [],
"created_by": {
"@type": "user",
"@href": "/api/user/574",
"@representation": "minimal",
"id": 574,
"login": "spinnaker"
},
"updated_at": "2019-09-04T10:48:12.782Z"
}
]
}'''
when:
V3Builds builds = client.v3builds("someToken", "org/repo", 1, "job.config")
then:
builds.builds.size() == 1
builds.builds[0].jobs[0].config.globalEnv == [
"REGION=eu-west-1",
"STACK_NAME=testing",
"A_USER=user@schibsted.com",
"A_PWD=[secure]",
"KEY_ID=MY_KEY",
"A_SECRET=[secure]",
"ROLE=arn:aws:iam::0123456789:role/myRole"
]
}
private void setResponse(String body) {
server.enqueue(
new MockResponse()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,44 @@ class ConfigSpec extends Specification {
null || null
}

@Unroll
def "should handle different env_var types"() {
given:
Config config = new Config()

when:
config.setGlobalEnv(globalEnv)

then:
config.globalEnv == expectedGlobalEnv

where:
globalEnv || expectedGlobalEnv
["KEY_1=value 1", "KEY_2=value 2"] || ["KEY_1=value 1", "KEY_2=value 2"]
"TF_INPUT=false " +
"SOME_KEY=\"with spaces\" " +
"ANOTHER_KEY=withoutspaces " +
"lowercase-key=\"string with=equals sign\" " +
"REGION=eu-west-1 " +
"STACK_NAME=testing " +
"A_USER=user@schibsted.com " +
"A_PWD=[secure] " +
"KEY_ID=\"SOMEKEYID\" " +
"SOME_SECRET=[secure] " +
"ROLE='arn:aws:iam::0123456789:role/MyRole' " +
"KEY=whatabout=this\\\\ " +
"KEY2=\"and=this\\\\\"" || ["TF_INPUT=false",
"SOME_KEY=with spaces",
"ANOTHER_KEY=withoutspaces",
"lowercase-key=string with=equals sign",
"REGION=eu-west-1",
"STACK_NAME=testing",
"A_USER=user@schibsted.com",
"A_PWD=[secure]",
"KEY_ID=SOMEKEYID",
"SOME_SECRET=[secure]",
"ROLE=arn:aws:iam::0123456789:role/MyRole",
"KEY=whatabout=this\\\\",
"KEY2=and=this\\\\"]
}
}

0 comments on commit 093f121

Please sign in to comment.