Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ We use [semantic versioning](http://semver.org/):
- PATCH version when you make backwards compatible bug fixes.

# Next version
- [feature] _agent_: Access token can be passed via environment variable `TEAMSCALE_ACCESS_TOKEN`

# 35.1.0
- [feature] _agent_: Experimental support for Java 25 class files
- [fix] _agent_: Reported wrong version number in docker container
Expand Down
3 changes: 2 additions & 1 deletion agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,9 @@ patterns with `*`, `**` and `?`.
- `teamscale-user`: the username used to authenticate against Teamscale. The user account must have the
"Perform External Uploads" permission on the given project.
- `teamscale-access-token`: the access token of the user.
Alternatively you can also set the `TEAMSCALE_ACCESS_TOKEN` environment variable to that value.
- `teamscale-partition`: the partition within Teamscale to upload coverage to. A partition can be an arbitrary string
which can be used to encode e.g. the test environment or the tester. These can be individually toggled on or off in
which can be used to encode e.g. the test environment. These can be individually toggled on or off in
Teamscale's UI.
- `teamscale-revision`: the source control revision (e.g. SVN revision or Git hash) that has been used to build
the system under test. Teamscale uses this to map the coverage to the corresponding source code. For an alternative see `teamscale-revision-manifest-jar`.
Expand Down
7 changes: 6 additions & 1 deletion agent/src/main/java/com/teamscale/jacoco/agent/PreMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ public class PreMain {
/** Environment variable from which to read the config file to use. */
private static final String CONFIG_FILE_ENVIRONMENT_VARIABLE = "TEAMSCALE_JAVA_PROFILER_CONFIG_FILE";

/** Environment variable from which to read the Teamscale access token. */
private static final String ACCESS_TOKEN_ENVIRONMENT_VARIABLE = "TEAMSCALE_ACCESS_TOKEN";

/**
* Entry point for the agent, called by the JVM.
*/
Expand Down Expand Up @@ -138,11 +141,13 @@ private static Pair<AgentOptions, List<Exception>> getAndApplyAgentOptions(Strin
"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.");
}

String environmentAccessToken = System.getenv(ACCESS_TOKEN_ENVIRONMENT_VARIABLE);

Pair<AgentOptions, List<Exception>> parseResult;
AgentOptions agentOptions;
try {
parseResult = AgentOptionsParser.parse(
options, environmentConfigId, environmentConfigFile, credentials,
options, environmentConfigId, environmentConfigFile, credentials, environmentAccessToken,
delayedLogger);
agentOptions = parseResult.getFirst();
} catch (AgentOptionParseException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,34 +62,40 @@ public class AgentOptionsParser {
private final TeamscaleConfig teamscaleConfig;
private final String environmentConfigId;
private final String environmentConfigFile;
@Nullable
private final TeamscaleCredentials credentials;
@Nullable
private final String environmentAccessToken;
private final List<Exception> collectedErrors;

/**
* Parses the given command-line options.
*
* @param environmentConfigId The Profiler configuration ID given via an environment variable.
* @param environmentConfigFile The Profiler configuration file given via an environment variable.
* @param environmentConfigId The Profiler configuration ID given via an environment variable.
* @param environmentConfigFile The Profiler configuration file given via an environment variable.
* @param credentials Optional Teamscale credentials from a teamscale.properties file.
* @param environmentAccessToken Optional access token for accessing Teamscale, read from an env variable.
*/
public static Pair<AgentOptions, List<Exception>> parse(String optionsString, String environmentConfigId,
String environmentConfigFile,
@Nullable TeamscaleCredentials credentials,
String environmentConfigFile, @Nullable TeamscaleCredentials credentials,
@Nullable String environmentAccessToken,
ILogger logger) throws AgentOptionParseException, AgentOptionReceiveException {
AgentOptionsParser parser = new AgentOptionsParser(logger, environmentConfigId, environmentConfigFile,
credentials);
credentials, environmentAccessToken);
AgentOptions options = parser.parse(optionsString);
return Pair.createPair(options, parser.getCollectedErrors());
}

@VisibleForTesting
AgentOptionsParser(ILogger logger, String environmentConfigId, String environmentConfigFile,
TeamscaleCredentials credentials) {
@Nullable TeamscaleCredentials credentials, @Nullable String environmentAccessToken) {
this.logger = logger;
this.filePatternResolver = new FilePatternResolver(logger);
this.teamscaleConfig = new TeamscaleConfig(logger, filePatternResolver);
this.environmentConfigId = environmentConfigId;
this.environmentConfigFile = environmentConfigFile;
this.credentials = credentials;
this.environmentAccessToken = environmentAccessToken;
this.collectedErrors = Lists.newArrayList();
}

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

if (credentials != null) {
options.teamscaleServer.url = credentials.url;
options.teamscaleServer.userName = credentials.userName;
options.teamscaleServer.userAccessToken = credentials.accessKey;
}
presetCredentialOptions(options);

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

private void presetCredentialOptions(AgentOptions options) {
if (credentials != null) {
options.teamscaleServer.url = credentials.url;
options.teamscaleServer.userName = credentials.userName;
options.teamscaleServer.userAccessToken = credentials.accessKey;
}
if (environmentAccessToken != null) {
options.teamscaleServer.userAccessToken = environmentAccessToken;
}
}

/**
* Stores the agent options for proxies in the {@link TeamscaleProxySystemProperties} and overwrites the password
* with the password found in the proxy-password-file if necessary.
Expand All @@ -179,7 +192,7 @@ private void handleConfigId(AgentOptions options) throws AgentOptionReceiveExcep
readConfigFromTeamscale(options);
}

private void handleConfigFile(AgentOptions options) throws AgentOptionParseException, AgentOptionReceiveException {
private void handleConfigFile(AgentOptions options) throws AgentOptionParseException {
if (environmentConfigFile != null) {
handleOptionPart(options, "config-file=" + environmentConfigFile);
}
Expand All @@ -195,7 +208,7 @@ private void handleConfigFile(AgentOptions options) throws AgentOptionParseExcep
* Parses and stores the given option in the format <code>key=value</code>.
*/
private void handleOptionPart(AgentOptions options,
String optionPart) throws AgentOptionParseException, AgentOptionReceiveException {
String optionPart) throws AgentOptionParseException {
Pair<String, String> keyAndValue = parseOption(optionPart);
handleOption(options, keyAndValue.getFirst(), keyAndValue.getSecond());
}
Expand All @@ -204,7 +217,7 @@ private void handleOptionPart(AgentOptions options,
* Parses and stores the option with the given key and value.
*/
private void handleOption(AgentOptions options,
String key, String value) throws AgentOptionParseException, AgentOptionReceiveException {
String key, String value) throws AgentOptionParseException {
if (key.startsWith(DEBUG)) {
handleDebugOption(options, value);
return;
Expand Down Expand Up @@ -299,7 +312,7 @@ private Pair<String, String> parseOption(String optionPart) throws AgentOptionPa
* @return true if it has successfully processed the given option.
*/
private boolean handleAgentOptions(AgentOptions options, String key, String value)
throws AgentOptionParseException, AgentOptionReceiveException {
throws AgentOptionParseException {
switch (key) {
case "config-id":
options.teamscaleServer.configId = value;
Expand Down Expand Up @@ -447,7 +460,7 @@ public static <T extends Enum<T>> T parseEnumValue(String key, String value, Cla
* excludes=third.party.*
*/
private void readConfigFromFile(AgentOptions options,
File configFile) throws AgentOptionParseException, AgentOptionReceiveException {
File configFile) throws AgentOptionParseException {
try {
String content = FileSystemUtils.readFileUTF8(configFile);
readConfigFromString(options, content);
Expand All @@ -460,8 +473,7 @@ private void readConfigFromFile(AgentOptions options,
}
}

private void readConfigFromString(AgentOptions options,
String content) throws AgentOptionParseException, AgentOptionReceiveException {
private void readConfigFromString(AgentOptions options, String content) {
List<String> configFileKeyValues = org.conqat.lib.commons.string.StringUtils.splitLinesAsList(
content);
for (String optionKeyValue : configFileKeyValues) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public class TeamscalePropertiesUtils {
.resolve("teamscale.properties");

/**
* Tries to open {@link #TEAMSCALE_PROPERTIES_PATH} and parse that properties file to obtain {@link
* TeamscaleCredentials}.
* Tries to open {@link #TEAMSCALE_PROPERTIES_PATH} and parse that properties file to obtain
* {@link TeamscaleCredentials}.
*
* @return the parsed credentials or null in case the teamscale.properties file doesn't exist.
* @throws AgentOptionParseException in case the teamscale.properties file exists but can't be read or parsed.
Expand All @@ -32,7 +32,8 @@ public static TeamscaleCredentials parseCredentials() throws AgentOptionParseExc
/**
* Same as {@link #parseCredentials()} but testable since the path is not hardcoded.
*/
/*package*/ static TeamscaleCredentials parseCredentials(
/*package*/
static TeamscaleCredentials parseCredentials(
Path teamscalePropertiesPath) throws AgentOptionParseException {
if (!Files.exists(teamscalePropertiesPath)) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public void testUploadMethodRecognition() throws Exception {
@Test
public void testUploadMethodRecognitionWithTeamscaleProperties() throws Exception {
TeamscaleCredentials credentials = new TeamscaleCredentials(HttpUrl.get("http://localhost"), "user", "key");
AgentOptionsParser parser = new AgentOptionsParser(new CommandLineLogger(), null, null, credentials);
AgentOptionsParser parser = new AgentOptionsParser(new CommandLineLogger(), null, null, credentials, null);

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

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

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

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

@Test
public void accessTokenFromEnvironment() throws Exception {
assertThat(parseAndThrow(
"teamscale-server-url=teamscale.com,teamscale-user=user,teamscale-partition=p,teamscale-project=p",
"envtoken").teamscaleServer.userAccessToken).isEqualTo("envtoken");
// command line overrides env variable
assertThat(parseAndThrow(
"teamscale-server-url=teamscale.com,teamscale-user=user,teamscale-access-token=commandlinetoken,teamscale-partition=p,teamscale-project=p",
"envtoken").teamscaleServer.userAccessToken).isEqualTo("commandlinetoken");
}

@Test
public void notGivingAnyOptionsShouldBeOK() throws Exception {
parseAndThrow("");
Expand All @@ -265,11 +276,13 @@ public void mustPreserveDefaultExcludes() throws Exception {

@Test
public void teamscalePropertiesCredentialsUsedAsDefaultButOverridable() throws Exception {
assertThat(parseAndThrow(new AgentOptionsParser(new CommandLineLogger(), null, null, teamscaleCredentials),
"teamscale-project=p,teamscale-partition=p").teamscaleServer.userName).isEqualTo(
assertThat(
parseAndThrow(new AgentOptionsParser(new CommandLineLogger(), null, null, teamscaleCredentials, null),
"teamscale-project=p,teamscale-partition=p").teamscaleServer.userName).isEqualTo(
"user");
assertThat(parseAndThrow(new AgentOptionsParser(new CommandLineLogger(), null, null, teamscaleCredentials),
"teamscale-project=p,teamscale-partition=p,teamscale-user=user2").teamscaleServer.userName).isEqualTo(
assertThat(
parseAndThrow(new AgentOptionsParser(new CommandLineLogger(), null, null, teamscaleCredentials, null),
"teamscale-project=p,teamscale-partition=p,teamscale-user=user2").teamscaleServer.userName).isEqualTo(
"user2");
}

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

private AgentOptions parseAndThrow(String options) throws Exception {
AgentOptionsParser parser = new AgentOptionsParser(new CommandLineLogger(), null, null, null);
AgentOptionsParser parser = new AgentOptionsParser(new CommandLineLogger(), null, null, null, null);
return parseAndThrow(parser, options);
}

private AgentOptions parseAndThrow(String options, String environmentAccessToken) throws Exception {
AgentOptionsParser parser = new AgentOptionsParser(new CommandLineLogger(), null, null, null,
environmentAccessToken);
return parseAndThrow(parser, options);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,11 +482,11 @@ private static Predicate<String> excludeFilter(String filterString) throws Excep
}

private static AgentOptionsParser getAgentOptionsParserWithDummyLogger() {
return new AgentOptionsParser(new CommandLineLogger(), null, null, null);
return new AgentOptionsParser(new CommandLineLogger(), null, null, null, null);
}

private static AgentOptionsParser getAgentOptionsParserWithDummyLoggerAndCredentials(TeamscaleCredentials credentials) {
return new AgentOptionsParser(new CommandLineLogger(), null, null, credentials);
return new AgentOptionsParser(new CommandLineLogger(), null, null, credentials, null);
}

/**
Expand Down
Loading