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
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,8 @@ Thus, the default behaviour with no placeholders is the same as adding a search
For example, `file:/tmp/config` is the same as `file:/tmp/config,file:/tmp/config/\{label}`.
This behavior can be disabled by setting `spring.cloud.config.server.native.addLabelLocations=false`.

If the request contains several labels (a comma-separated list), the last label takes precedence over the earlier ones, as it does for the Git and SVN backends.
Each label is resolved on its own, and the locations the labels share come last.
Before this behavior was introduced, the first label took precedence.
To restore that behavior, set `spring.cloud.config.server.native.lastLabelWins=false`.

Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ public class NativeEnvironmentProperties implements EnvironmentRepositoryPropert
*/
private Boolean addLabelLocations = true;

/**
* Flag to determine whether, when several labels are requested, the last label takes
* precedence over the earlier ones (default true). If false, the first label takes
* precedence, as it did before this property was introduced.
*/
private Boolean lastLabelWins = true;

private String defaultLabel = "master";

/**
Expand Down Expand Up @@ -66,6 +73,14 @@ public void setAddLabelLocations(Boolean addLabelLocations) {
this.addLabelLocations = addLabelLocations;
}

public Boolean getLastLabelWins() {
return this.lastLabelWins;
}

public void setLastLabelWins(Boolean lastLabelWins) {
this.lastLabelWins = lastLabelWins;
}

public String getDefaultLabel() {
return this.defaultLabel;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
package org.springframework.cloud.config.server.environment;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -85,6 +87,8 @@ public class NativeEnvironmentRepository implements EnvironmentRepository, Searc
*/
private boolean addLabelLocations;

private boolean lastLabelWins = true;

/**
* Version string to be reported for native repository.
*/
Expand All @@ -100,6 +104,7 @@ public NativeEnvironmentRepository(ConfigurableEnvironment environment, NativeEn
ObservationRegistry observationRegistry) {
this.environment = environment;
this.addLabelLocations = properties.getAddLabelLocations();
this.lastLabelWins = properties.getLastLabelWins();
this.defaultLabel = properties.getDefaultLabel();
this.failOnError = properties.getFailOnError();
this.order = properties.getOrder();
Expand All @@ -124,6 +129,14 @@ public void setAddLabelLocations(boolean addLabelLocations) {
this.addLabelLocations = addLabelLocations;
}

public boolean isLastLabelWins() {
return this.lastLabelWins;
}

public void setLastLabelWins(boolean lastLabelWins) {
this.lastLabelWins = lastLabelWins;
}

public String getDefaultLabel() {
return this.defaultLabel;
}
Expand All @@ -139,7 +152,36 @@ public Environment findOne(String config, String profile, String label) {

@Override
public Environment findOne(String config, String profile, String label, boolean includeOrigin) {
if (!this.lastLabelWins || label == null || !label.contains(",")) {
return findOneForLabel(config, profile, label, includeOrigin);
}
// Resolve one label at a time, so that the last label takes precedence over the
// earlier ones as in the SCM repositories. Resolving them together would let
// Spring Boot interleave the labels by profile, giving the first label
// precedence.
List<String> labels = new ArrayList<>(Arrays.asList(StringUtils.commaDelimitedListToStringArray(label)));
Collections.reverse(labels);
Environment result = null;
Map<String, PropertySource> sources = new LinkedHashMap<>();
for (String singleLabel : labels) {
Environment environment = findOneForLabel(config, profile, singleLabel, includeOrigin);
if (result == null) {
result = new Environment(environment.getName(), environment.getProfiles(), label,
environment.getVersion(), environment.getState());
}
for (PropertySource source : environment.getPropertySources()) {
// A property source found for several labels comes from a location the
// labels share, which has a lower precedence than the label locations,
// so keep it at its last position
sources.remove(source.getName());
sources.put(source.getName(), source);
}
}
sources.values().forEach(result::add);
return result;
}

private Environment findOneForLabel(String config, String profile, String label, boolean includeOrigin) {
try {
ConfigurableEnvironment environment = getEnvironment(config, profile, label);
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,19 @@ public void locationAddLabelLocations() {

@Test
public void locationAddMultipleLabelLocations() {
this.repository.setSearchLocations("classpath:/test/dev/");
Environment environment = this.repository.findOne("foo", "development", "ignore,applicationxyz");
// the last label wins, the location shared by the labels comes last
assertThat(environment.getPropertySources()).hasSize(3);
assertThat(environment.getPropertySources().get(0).getSource().get("foo")).isEqualTo("default-app");
assertThat(environment.getPropertySources().get(1).getSource().get("foo")).isEqualTo("app");
assertThat(environment.getPropertySources().get(2).getSource().get("foo")).isEqualTo("dev_bar");
assertThat(environment.getLabel()).isEqualTo("ignore,applicationxyz");
}

@Test
public void locationAddMultipleLabelLocationsFirstLabelWins() {
this.repository.setLastLabelWins(false);
this.repository.setSearchLocations("classpath:/test/dev/");
Environment environment = this.repository.findOne("foo", "development", "ignore,applicationxyz");
assertThat(environment.getPropertySources()).hasSize(3);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
import java.nio.file.Path;

import io.micrometer.observation.ObservationRegistry;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import org.springframework.cloud.config.server.environment.EnvironmentRepository;
Expand Down Expand Up @@ -57,11 +55,4 @@ public EnvironmentRepository repository() {
return this.fixture;
}

@Override
@Test
@Disabled("TODO-issue: Label directories are added as search locations, so labels are interleaved by profile and the first label wins")
public void lastLabelTakesPrecedence() throws Exception {
super.lastLabelTakesPrecedence();
}

}
Loading