Skip to content

Commit 88d20cc

Browse files
authored
Merge pull request #694 from cqse/access_token_from_environment
read access token from environment variable
2 parents 9bd34a1 + 516552e commit 88d20cc

7 files changed

Lines changed: 75 additions & 35 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ We use [semantic versioning](http://semver.org/):
55
- PATCH version when you make backwards compatible bug fixes.
66

77
# Next version
8+
- [feature] _agent_: Access token can be passed via environment variable `TEAMSCALE_ACCESS_TOKEN`
9+
810
# 35.1.0
911
- [feature] _agent_: Experimental support for Java 25 class files
1012
- [fix] _agent_: Reported wrong version number in docker container

agent/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,9 @@ patterns with `*`, `**` and `?`.
137137
- `teamscale-user`: the username used to authenticate against Teamscale. The user account must have the
138138
"Perform External Uploads" permission on the given project.
139139
- `teamscale-access-token`: the access token of the user.
140+
Alternatively you can also set the `TEAMSCALE_ACCESS_TOKEN` environment variable to that value.
140141
- `teamscale-partition`: the partition within Teamscale to upload coverage to. A partition can be an arbitrary string
141-
which can be used to encode e.g. the test environment or the tester. These can be individually toggled on or off in
142+
which can be used to encode e.g. the test environment. These can be individually toggled on or off in
142143
Teamscale's UI.
143144
- `teamscale-revision`: the source control revision (e.g. SVN revision or Git hash) that has been used to build
144145
the system under test. Teamscale uses this to map the coverage to the corresponding source code. For an alternative see `teamscale-revision-manifest-jar`.

agent/src/main/java/com/teamscale/jacoco/agent/PreMain.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ public class PreMain {
5555
/** Environment variable from which to read the config file to use. */
5656
private static final String CONFIG_FILE_ENVIRONMENT_VARIABLE = "TEAMSCALE_JAVA_PROFILER_CONFIG_FILE";
5757

58+
/** Environment variable from which to read the Teamscale access token. */
59+
private static final String ACCESS_TOKEN_ENVIRONMENT_VARIABLE = "TEAMSCALE_ACCESS_TOKEN";
60+
5861
/**
5962
* Entry point for the agent, called by the JVM.
6063
*/
@@ -138,11 +141,13 @@ private static Pair<AgentOptions, List<Exception>> getAndApplyAgentOptions(Strin
138141
"No explicit teamscale.properties file given. Looking for Teamscale credentials in a config file or via a command line argument. This is expected unless the installer based setup was used.");
139142
}
140143

144+
String environmentAccessToken = System.getenv(ACCESS_TOKEN_ENVIRONMENT_VARIABLE);
145+
141146
Pair<AgentOptions, List<Exception>> parseResult;
142147
AgentOptions agentOptions;
143148
try {
144149
parseResult = AgentOptionsParser.parse(
145-
options, environmentConfigId, environmentConfigFile, credentials,
150+
options, environmentConfigId, environmentConfigFile, credentials, environmentAccessToken,
146151
delayedLogger);
147152
agentOptions = parseResult.getFirst();
148153
} catch (AgentOptionParseException e) {

agent/src/main/java/com/teamscale/jacoco/agent/options/AgentOptionsParser.java

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -62,34 +62,40 @@ public class AgentOptionsParser {
6262
private final TeamscaleConfig teamscaleConfig;
6363
private final String environmentConfigId;
6464
private final String environmentConfigFile;
65+
@Nullable
6566
private final TeamscaleCredentials credentials;
67+
@Nullable
68+
private final String environmentAccessToken;
6669
private final List<Exception> collectedErrors;
6770

6871
/**
6972
* Parses the given command-line options.
7073
*
71-
* @param environmentConfigId The Profiler configuration ID given via an environment variable.
72-
* @param environmentConfigFile The Profiler configuration file given via an environment variable.
74+
* @param environmentConfigId The Profiler configuration ID given via an environment variable.
75+
* @param environmentConfigFile The Profiler configuration file given via an environment variable.
76+
* @param credentials Optional Teamscale credentials from a teamscale.properties file.
77+
* @param environmentAccessToken Optional access token for accessing Teamscale, read from an env variable.
7378
*/
7479
public static Pair<AgentOptions, List<Exception>> parse(String optionsString, String environmentConfigId,
75-
String environmentConfigFile,
76-
@Nullable TeamscaleCredentials credentials,
80+
String environmentConfigFile, @Nullable TeamscaleCredentials credentials,
81+
@Nullable String environmentAccessToken,
7782
ILogger logger) throws AgentOptionParseException, AgentOptionReceiveException {
7883
AgentOptionsParser parser = new AgentOptionsParser(logger, environmentConfigId, environmentConfigFile,
79-
credentials);
84+
credentials, environmentAccessToken);
8085
AgentOptions options = parser.parse(optionsString);
8186
return Pair.createPair(options, parser.getCollectedErrors());
8287
}
8388

8489
@VisibleForTesting
8590
AgentOptionsParser(ILogger logger, String environmentConfigId, String environmentConfigFile,
86-
TeamscaleCredentials credentials) {
91+
@Nullable TeamscaleCredentials credentials, @Nullable String environmentAccessToken) {
8792
this.logger = logger;
8893
this.filePatternResolver = new FilePatternResolver(logger);
8994
this.teamscaleConfig = new TeamscaleConfig(logger, filePatternResolver);
9095
this.environmentConfigId = environmentConfigId;
9196
this.environmentConfigFile = environmentConfigFile;
9297
this.credentials = credentials;
98+
this.environmentAccessToken = environmentAccessToken;
9399
this.collectedErrors = Lists.newArrayList();
94100
}
95101

@@ -121,11 +127,7 @@ public void throwOnCollectedErrors() throws Exception {
121127
AgentOptions options = new AgentOptions(logger);
122128
options.originalOptionsString = optionsString;
123129

124-
if (credentials != null) {
125-
options.teamscaleServer.url = credentials.url;
126-
options.teamscaleServer.userName = credentials.userName;
127-
options.teamscaleServer.userAccessToken = credentials.accessKey;
128-
}
130+
presetCredentialOptions(options);
129131

130132
if (!StringUtils.isEmpty(optionsString)) {
131133
String[] optionParts = optionsString.split(",");
@@ -153,6 +155,17 @@ public void throwOnCollectedErrors() throws Exception {
153155
return options;
154156
}
155157

158+
private void presetCredentialOptions(AgentOptions options) {
159+
if (credentials != null) {
160+
options.teamscaleServer.url = credentials.url;
161+
options.teamscaleServer.userName = credentials.userName;
162+
options.teamscaleServer.userAccessToken = credentials.accessKey;
163+
}
164+
if (environmentAccessToken != null) {
165+
options.teamscaleServer.userAccessToken = environmentAccessToken;
166+
}
167+
}
168+
156169
/**
157170
* Stores the agent options for proxies in the {@link TeamscaleProxySystemProperties} and overwrites the password
158171
* with the password found in the proxy-password-file if necessary.
@@ -179,7 +192,7 @@ private void handleConfigId(AgentOptions options) throws AgentOptionReceiveExcep
179192
readConfigFromTeamscale(options);
180193
}
181194

182-
private void handleConfigFile(AgentOptions options) throws AgentOptionParseException, AgentOptionReceiveException {
195+
private void handleConfigFile(AgentOptions options) throws AgentOptionParseException {
183196
if (environmentConfigFile != null) {
184197
handleOptionPart(options, "config-file=" + environmentConfigFile);
185198
}
@@ -195,7 +208,7 @@ private void handleConfigFile(AgentOptions options) throws AgentOptionParseExcep
195208
* Parses and stores the given option in the format <code>key=value</code>.
196209
*/
197210
private void handleOptionPart(AgentOptions options,
198-
String optionPart) throws AgentOptionParseException, AgentOptionReceiveException {
211+
String optionPart) throws AgentOptionParseException {
199212
Pair<String, String> keyAndValue = parseOption(optionPart);
200213
handleOption(options, keyAndValue.getFirst(), keyAndValue.getSecond());
201214
}
@@ -204,7 +217,7 @@ private void handleOptionPart(AgentOptions options,
204217
* Parses and stores the option with the given key and value.
205218
*/
206219
private void handleOption(AgentOptions options,
207-
String key, String value) throws AgentOptionParseException, AgentOptionReceiveException {
220+
String key, String value) throws AgentOptionParseException {
208221
if (key.startsWith(DEBUG)) {
209222
handleDebugOption(options, value);
210223
return;
@@ -299,7 +312,7 @@ private Pair<String, String> parseOption(String optionPart) throws AgentOptionPa
299312
* @return true if it has successfully processed the given option.
300313
*/
301314
private boolean handleAgentOptions(AgentOptions options, String key, String value)
302-
throws AgentOptionParseException, AgentOptionReceiveException {
315+
throws AgentOptionParseException {
303316
switch (key) {
304317
case "config-id":
305318
options.teamscaleServer.configId = value;
@@ -447,7 +460,7 @@ public static <T extends Enum<T>> T parseEnumValue(String key, String value, Cla
447460
* excludes=third.party.*
448461
*/
449462
private void readConfigFromFile(AgentOptions options,
450-
File configFile) throws AgentOptionParseException, AgentOptionReceiveException {
463+
File configFile) throws AgentOptionParseException {
451464
try {
452465
String content = FileSystemUtils.readFileUTF8(configFile);
453466
readConfigFromString(options, content);
@@ -460,8 +473,7 @@ private void readConfigFromFile(AgentOptions options,
460473
}
461474
}
462475

463-
private void readConfigFromString(AgentOptions options,
464-
String content) throws AgentOptionParseException, AgentOptionReceiveException {
476+
private void readConfigFromString(AgentOptions options, String content) {
465477
List<String> configFileKeyValues = org.conqat.lib.commons.string.StringUtils.splitLinesAsList(
466478
content);
467479
for (String optionKeyValue : configFileKeyValues) {

agent/src/main/java/com/teamscale/jacoco/agent/options/TeamscalePropertiesUtils.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ public class TeamscalePropertiesUtils {
1919
.resolve("teamscale.properties");
2020

2121
/**
22-
* Tries to open {@link #TEAMSCALE_PROPERTIES_PATH} and parse that properties file to obtain {@link
23-
* TeamscaleCredentials}.
22+
* Tries to open {@link #TEAMSCALE_PROPERTIES_PATH} and parse that properties file to obtain
23+
* {@link TeamscaleCredentials}.
2424
*
2525
* @return the parsed credentials or null in case the teamscale.properties file doesn't exist.
2626
* @throws AgentOptionParseException in case the teamscale.properties file exists but can't be read or parsed.
@@ -32,7 +32,8 @@ public static TeamscaleCredentials parseCredentials() throws AgentOptionParseExc
3232
/**
3333
* Same as {@link #parseCredentials()} but testable since the path is not hardcoded.
3434
*/
35-
/*package*/ static TeamscaleCredentials parseCredentials(
35+
/*package*/
36+
static TeamscaleCredentials parseCredentials(
3637
Path teamscalePropertiesPath) throws AgentOptionParseException {
3738
if (!Files.exists(teamscalePropertiesPath)) {
3839
return null;

agent/src/test/java/com/teamscale/jacoco/agent/options/AgentOptionsParserTest.java

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public void testUploadMethodRecognition() throws Exception {
7272
@Test
7373
public void testUploadMethodRecognitionWithTeamscaleProperties() throws Exception {
7474
TeamscaleCredentials credentials = new TeamscaleCredentials(HttpUrl.get("http://localhost"), "user", "key");
75-
AgentOptionsParser parser = new AgentOptionsParser(new CommandLineLogger(), null, null, credentials);
75+
AgentOptionsParser parser = new AgentOptionsParser(new CommandLineLogger(), null, null, credentials, null);
7676

7777
assertThat(parseAndThrow(null).determineUploadMethod()).isEqualTo(AgentOptions.EUploadMethod.LOCAL_DISK);
7878
assertThat(parseAndThrow("azure-url=azure.com,azure-key=key").determineUploadMethod()).isEqualTo(
@@ -103,7 +103,7 @@ public void environmentConfigIdOverridesCommandLineOptions() throws Exception {
103103
registration.profilerConfiguration.configurationOptions = "teamscale-partition=foo";
104104
mockWebServer.enqueue(new MockResponse().setBody(JsonUtils.serialize(registration)));
105105
AgentOptionsParser parser = new AgentOptionsParser(new CommandLineLogger(), "my-config",
106-
null, teamscaleCredentials);
106+
null, teamscaleCredentials, null);
107107
AgentOptions options = parseAndThrow(parser, "teamscale-partition=bar");
108108

109109
assertThat(options.teamscaleServer.partition).isEqualTo("foo");
@@ -112,7 +112,7 @@ public void environmentConfigIdOverridesCommandLineOptions() throws Exception {
112112
@Test
113113
public void environmentConfigFileOverridesCommandLineOptions() throws Exception {
114114
AgentOptionsParser parser = new AgentOptionsParser(new CommandLineLogger(), null, configFile.toString(),
115-
teamscaleCredentials);
115+
teamscaleCredentials, null);
116116
AgentOptions options = parseAndThrow(parser, "teamscale-partition=from-command-line");
117117

118118
assertThat(options.teamscaleServer.partition).isEqualTo("from-config-file");
@@ -127,7 +127,7 @@ public void environmentConfigFileOverridesConfigId() throws Exception {
127127
registration.profilerConfiguration.configurationOptions = "teamscale-partition=from-config-id";
128128
mockWebServer.enqueue(new MockResponse().setBody(JsonUtils.serialize(registration)));
129129
AgentOptionsParser parser = new AgentOptionsParser(new CommandLineLogger(), "my-config", configFile.toString(),
130-
teamscaleCredentials);
130+
teamscaleCredentials, null);
131131
AgentOptions options = parseAndThrow(parser, "teamscale-partition=from-command-line");
132132

133133
assertThat(options.teamscaleServer.partition).isEqualTo("from-config-file");
@@ -245,11 +245,22 @@ public void environmentConfigIdDoesNotExist() {
245245
mockWebServer.enqueue(new MockResponse().setResponseCode(404).setBody("invalid-config-id does not exist"));
246246
assertThatThrownBy(
247247
() -> new AgentOptionsParser(new CommandLineLogger(), "invalid-config-id", null,
248-
teamscaleCredentials).parse(
248+
teamscaleCredentials, null).parse(
249249
"")
250250
).isInstanceOf(AgentOptionReceiveException.class).hasMessageContaining("invalid-config-id does not exist");
251251
}
252252

253+
@Test
254+
public void accessTokenFromEnvironment() throws Exception {
255+
assertThat(parseAndThrow(
256+
"teamscale-server-url=teamscale.com,teamscale-user=user,teamscale-partition=p,teamscale-project=p",
257+
"envtoken").teamscaleServer.userAccessToken).isEqualTo("envtoken");
258+
// command line overrides env variable
259+
assertThat(parseAndThrow(
260+
"teamscale-server-url=teamscale.com,teamscale-user=user,teamscale-access-token=commandlinetoken,teamscale-partition=p,teamscale-project=p",
261+
"envtoken").teamscaleServer.userAccessToken).isEqualTo("commandlinetoken");
262+
}
263+
253264
@Test
254265
public void notGivingAnyOptionsShouldBeOK() throws Exception {
255266
parseAndThrow("");
@@ -265,11 +276,13 @@ public void mustPreserveDefaultExcludes() throws Exception {
265276

266277
@Test
267278
public void teamscalePropertiesCredentialsUsedAsDefaultButOverridable() throws Exception {
268-
assertThat(parseAndThrow(new AgentOptionsParser(new CommandLineLogger(), null, null, teamscaleCredentials),
269-
"teamscale-project=p,teamscale-partition=p").teamscaleServer.userName).isEqualTo(
279+
assertThat(
280+
parseAndThrow(new AgentOptionsParser(new CommandLineLogger(), null, null, teamscaleCredentials, null),
281+
"teamscale-project=p,teamscale-partition=p").teamscaleServer.userName).isEqualTo(
270282
"user");
271-
assertThat(parseAndThrow(new AgentOptionsParser(new CommandLineLogger(), null, null, teamscaleCredentials),
272-
"teamscale-project=p,teamscale-partition=p,teamscale-user=user2").teamscaleServer.userName).isEqualTo(
283+
assertThat(
284+
parseAndThrow(new AgentOptionsParser(new CommandLineLogger(), null, null, teamscaleCredentials, null),
285+
"teamscale-project=p,teamscale-partition=p,teamscale-user=user2").teamscaleServer.userName).isEqualTo(
273286
"user2");
274287
}
275288

@@ -280,7 +293,13 @@ private AgentOptions parseAndThrow(AgentOptionsParser parser, String options) th
280293
}
281294

282295
private AgentOptions parseAndThrow(String options) throws Exception {
283-
AgentOptionsParser parser = new AgentOptionsParser(new CommandLineLogger(), null, null, null);
296+
AgentOptionsParser parser = new AgentOptionsParser(new CommandLineLogger(), null, null, null, null);
297+
return parseAndThrow(parser, options);
298+
}
299+
300+
private AgentOptions parseAndThrow(String options, String environmentAccessToken) throws Exception {
301+
AgentOptionsParser parser = new AgentOptionsParser(new CommandLineLogger(), null, null, null,
302+
environmentAccessToken);
284303
return parseAndThrow(parser, options);
285304
}
286305

agent/src/test/java/com/teamscale/jacoco/agent/options/AgentOptionsTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,11 +482,11 @@ private static Predicate<String> excludeFilter(String filterString) throws Excep
482482
}
483483

484484
private static AgentOptionsParser getAgentOptionsParserWithDummyLogger() {
485-
return new AgentOptionsParser(new CommandLineLogger(), null, null, null);
485+
return new AgentOptionsParser(new CommandLineLogger(), null, null, null, null);
486486
}
487487

488488
private static AgentOptionsParser getAgentOptionsParserWithDummyLoggerAndCredentials(TeamscaleCredentials credentials) {
489-
return new AgentOptionsParser(new CommandLineLogger(), null, null, credentials);
489+
return new AgentOptionsParser(new CommandLineLogger(), null, null, credentials, null);
490490
}
491491

492492
/**

0 commit comments

Comments
 (0)