Merge branch 'stable-2.16'
* stable-2.16: ChangeCleanupConfig: Remove unnecessary usage of regex in URL replacement AbandonIT: Add tests for changeCleanup.abandonMessage UrlFormatter#getChangeViewUrl: Remove @Nullable and simplify default implementation UrlFormatter#getSettingsUrl: Annotate section parameter as @Nullable MergeUtil: Include project name in "Reviewed-On" URL ChangeCleanupConfig: Inject UrlFormatter via DynamicItem Adjust more classes to inject UrlFormatter via DynamicItem Set version to 2.15.12-SNAPSHOT Set version to 2.15.11 Allow LFS-over-SSH created auth pass through ContainerAuthFilter Upgrade elasticsearch-rest-client to 6.6.1 ElasticContainer: Bump the test server version to 5.6.15 Change-Id: Ie90d450ddb16d165ed2d5ec91964d35b735214dd
This commit is contained in:
@@ -1058,8 +1058,8 @@ maven_jar(
|
|||||||
# and httpasyncclient as necessary.
|
# and httpasyncclient as necessary.
|
||||||
maven_jar(
|
maven_jar(
|
||||||
name = "elasticsearch-rest-client",
|
name = "elasticsearch-rest-client",
|
||||||
artifact = "org.elasticsearch.client:elasticsearch-rest-client:6.6.0",
|
artifact = "org.elasticsearch.client:elasticsearch-rest-client:6.6.1",
|
||||||
sha1 = "f0ce1ea819fedde731511b440b025e4fb5a2f5f7",
|
sha1 = "dc1c9284ffca28cd169fae2776c3956e90b76c00",
|
||||||
)
|
)
|
||||||
|
|
||||||
JACKSON_VERSION = "2.9.8"
|
JACKSON_VERSION = "2.9.8"
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableMap;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.flogger.FluentLogger;
|
import com.google.common.flogger.FluentLogger;
|
||||||
import com.google.common.io.BaseEncoding;
|
import com.google.common.io.BaseEncoding;
|
||||||
|
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||||
import com.google.gerrit.server.IdentifiedUser;
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
import com.google.gerrit.server.account.AccountState;
|
import com.google.gerrit.server.account.AccountState;
|
||||||
import com.google.gerrit.server.account.externalids.ExternalId;
|
import com.google.gerrit.server.account.externalids.ExternalId;
|
||||||
@@ -58,7 +59,7 @@ public class GerritPublicKeyChecker extends PublicKeyChecker {
|
|||||||
@Singleton
|
@Singleton
|
||||||
public static class Factory {
|
public static class Factory {
|
||||||
private final Provider<InternalAccountQuery> accountQueryProvider;
|
private final Provider<InternalAccountQuery> accountQueryProvider;
|
||||||
private final UrlFormatter urlFormatter;
|
private final DynamicItem<UrlFormatter> urlFormatter;
|
||||||
private final IdentifiedUser.GenericFactory userFactory;
|
private final IdentifiedUser.GenericFactory userFactory;
|
||||||
private final int maxTrustDepth;
|
private final int maxTrustDepth;
|
||||||
private final ImmutableMap<Long, Fingerprint> trusted;
|
private final ImmutableMap<Long, Fingerprint> trusted;
|
||||||
@@ -68,7 +69,7 @@ public class GerritPublicKeyChecker extends PublicKeyChecker {
|
|||||||
@GerritServerConfig Config cfg,
|
@GerritServerConfig Config cfg,
|
||||||
Provider<InternalAccountQuery> accountQueryProvider,
|
Provider<InternalAccountQuery> accountQueryProvider,
|
||||||
IdentifiedUser.GenericFactory userFactory,
|
IdentifiedUser.GenericFactory userFactory,
|
||||||
UrlFormatter urlFormatter) {
|
DynamicItem<UrlFormatter> urlFormatter) {
|
||||||
this.accountQueryProvider = accountQueryProvider;
|
this.accountQueryProvider = accountQueryProvider;
|
||||||
this.urlFormatter = urlFormatter;
|
this.urlFormatter = urlFormatter;
|
||||||
this.userFactory = userFactory;
|
this.userFactory = userFactory;
|
||||||
@@ -101,7 +102,7 @@ public class GerritPublicKeyChecker extends PublicKeyChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final Provider<InternalAccountQuery> accountQueryProvider;
|
private final Provider<InternalAccountQuery> accountQueryProvider;
|
||||||
private final UrlFormatter urlFormatter;
|
private final DynamicItem<UrlFormatter> urlFormatter;
|
||||||
private final IdentifiedUser.GenericFactory userFactory;
|
private final IdentifiedUser.GenericFactory userFactory;
|
||||||
|
|
||||||
private IdentifiedUser expectedUser;
|
private IdentifiedUser expectedUser;
|
||||||
@@ -144,7 +145,7 @@ public class GerritPublicKeyChecker extends PublicKeyChecker {
|
|||||||
private CheckResult checkIdsForExpectedUser(PGPPublicKey key) throws PGPException {
|
private CheckResult checkIdsForExpectedUser(PGPPublicKey key) throws PGPException {
|
||||||
Set<String> allowedUserIds = getAllowedUserIds(expectedUser);
|
Set<String> allowedUserIds = getAllowedUserIds(expectedUser);
|
||||||
if (allowedUserIds.isEmpty()) {
|
if (allowedUserIds.isEmpty()) {
|
||||||
Optional<String> settings = urlFormatter.getSettingsUrl("Identities");
|
Optional<String> settings = urlFormatter.get().getSettingsUrl("Identities");
|
||||||
return CheckResult.bad(
|
return CheckResult.bad(
|
||||||
"No identities found for user"
|
"No identities found for user"
|
||||||
+ (settings.isPresent() ? "; check " + settings.get() : ""));
|
+ (settings.isPresent() ? "; check " + settings.get() : ""));
|
||||||
|
|||||||
@@ -17,9 +17,12 @@ package com.google.gerrit.httpd;
|
|||||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||||
import static com.google.common.base.Strings.emptyToNull;
|
import static com.google.common.base.Strings.emptyToNull;
|
||||||
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
||||||
|
import static com.google.gerrit.extensions.api.lfs.LfsDefinitions.CONTENTTYPE_VND_GIT_LFS_JSON;
|
||||||
|
import static com.google.gerrit.httpd.GerritAuthModule.NOT_AUTHORIZED_LFS_URL_REGEX;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
|
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.gerrit.extensions.registration.DynamicItem;
|
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||||
import com.google.gerrit.httpd.restapi.RestApiServlet;
|
import com.google.gerrit.httpd.restapi.RestApiServlet;
|
||||||
import com.google.gerrit.server.AccessPath;
|
import com.google.gerrit.server.AccessPath;
|
||||||
@@ -32,6 +35,7 @@ import com.google.inject.Singleton;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
import javax.servlet.Filter;
|
import javax.servlet.Filter;
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
import javax.servlet.FilterConfig;
|
import javax.servlet.FilterConfig;
|
||||||
@@ -55,6 +59,9 @@ import org.eclipse.jgit.lib.Config;
|
|||||||
*/
|
*/
|
||||||
@Singleton
|
@Singleton
|
||||||
class ContainerAuthFilter implements Filter {
|
class ContainerAuthFilter implements Filter {
|
||||||
|
private static final String LFS_AUTH_PREFIX = "Ssh: ";
|
||||||
|
private static final Pattern LFS_ENDPOINT = Pattern.compile(NOT_AUTHORIZED_LFS_URL_REGEX);
|
||||||
|
|
||||||
private final DynamicItem<WebSession> session;
|
private final DynamicItem<WebSession> session;
|
||||||
private final AccountCache accountCache;
|
private final AccountCache accountCache;
|
||||||
private final Config config;
|
private final Config config;
|
||||||
@@ -93,6 +100,11 @@ class ContainerAuthFilter implements Filter {
|
|||||||
private boolean verify(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
|
private boolean verify(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
|
||||||
String username = RemoteUserUtil.getRemoteUser(req, loginHttpHeader);
|
String username = RemoteUserUtil.getRemoteUser(req, loginHttpHeader);
|
||||||
if (username == null) {
|
if (username == null) {
|
||||||
|
if (isLfsOverSshRequest(req)) {
|
||||||
|
// LFS-over-SSH auth request cannot be authorized by container
|
||||||
|
// therefore let it go through the filter
|
||||||
|
return true;
|
||||||
|
}
|
||||||
rsp.sendError(SC_FORBIDDEN);
|
rsp.sendError(SC_FORBIDDEN);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -111,4 +123,12 @@ class ContainerAuthFilter implements Filter {
|
|||||||
ws.setAccessPathOk(AccessPath.REST_API, true);
|
ws.setAccessPathOk(AccessPath.REST_API, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isLfsOverSshRequest(HttpServletRequest req) {
|
||||||
|
String hdr = req.getHeader(AUTHORIZATION);
|
||||||
|
return CONTENTTYPE_VND_GIT_LFS_JSON.equals(req.getContentType())
|
||||||
|
&& !Strings.isNullOrEmpty(hdr)
|
||||||
|
&& hdr.startsWith(LFS_AUTH_PREFIX)
|
||||||
|
&& LFS_ENDPOINT.matcher(req.getRequestURI()).matches();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import javax.servlet.Filter;
|
|||||||
|
|
||||||
/** Configures filter for authenticating REST requests. */
|
/** Configures filter for authenticating REST requests. */
|
||||||
public class GerritAuthModule extends ServletModule {
|
public class GerritAuthModule extends ServletModule {
|
||||||
private static final String NOT_AUTHORIZED_LFS_URL_REGEX = "^(?:(?!/a/))" + LFS_URL_WO_AUTH_REGEX;
|
static final String NOT_AUTHORIZED_LFS_URL_REGEX = "^(?:(?!/a/))" + LFS_URL_WO_AUTH_REGEX;
|
||||||
private final AuthConfig authConfig;
|
private final AuthConfig authConfig;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
package com.google.gerrit.server.config;
|
package com.google.gerrit.server.config;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||||
import com.google.gerrit.server.config.ScheduleConfig.Schedule;
|
import com.google.gerrit.server.config.ScheduleConfig.Schedule;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
@@ -34,17 +35,19 @@ public class ChangeCleanupConfig {
|
|||||||
+ "\n"
|
+ "\n"
|
||||||
+ "If this change is still wanted it should be restored.";
|
+ "If this change is still wanted it should be restored.";
|
||||||
|
|
||||||
|
private final DynamicItem<UrlFormatter> urlFormatter;
|
||||||
private final Optional<Schedule> schedule;
|
private final Optional<Schedule> schedule;
|
||||||
private final long abandonAfter;
|
private final long abandonAfter;
|
||||||
private final boolean abandonIfMergeable;
|
private final boolean abandonIfMergeable;
|
||||||
private final String abandonMessage;
|
private final String abandonMessage;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ChangeCleanupConfig(@GerritServerConfig Config cfg, UrlFormatter urlFormatter) {
|
ChangeCleanupConfig(@GerritServerConfig Config cfg, DynamicItem<UrlFormatter> urlFormatter) {
|
||||||
|
this.urlFormatter = urlFormatter;
|
||||||
schedule = ScheduleConfig.createSchedule(cfg, SECTION);
|
schedule = ScheduleConfig.createSchedule(cfg, SECTION);
|
||||||
abandonAfter = readAbandonAfter(cfg);
|
abandonAfter = readAbandonAfter(cfg);
|
||||||
abandonIfMergeable = cfg.getBoolean(SECTION, null, KEY_ABANDON_IF_MERGEABLE, true);
|
abandonIfMergeable = cfg.getBoolean(SECTION, null, KEY_ABANDON_IF_MERGEABLE, true);
|
||||||
abandonMessage = readAbandonMessage(cfg, urlFormatter);
|
abandonMessage = readAbandonMessage(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long readAbandonAfter(Config cfg) {
|
private long readAbandonAfter(Config cfg) {
|
||||||
@@ -53,18 +56,9 @@ public class ChangeCleanupConfig {
|
|||||||
return abandonAfter >= 0 ? abandonAfter : 0;
|
return abandonAfter >= 0 ? abandonAfter : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String readAbandonMessage(Config cfg, UrlFormatter urlFormatter) {
|
private String readAbandonMessage(Config cfg) {
|
||||||
String abandonMessage = cfg.getString(SECTION, null, KEY_ABANDON_MESSAGE);
|
String abandonMessage = cfg.getString(SECTION, null, KEY_ABANDON_MESSAGE);
|
||||||
if (Strings.isNullOrEmpty(abandonMessage)) {
|
return Strings.isNullOrEmpty(abandonMessage) ? DEFAULT_ABANDON_MESSAGE : abandonMessage;
|
||||||
abandonMessage = DEFAULT_ABANDON_MESSAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
String docUrl = urlFormatter.getDocUrl("user-change-cleanup.html", "auto-abandon").orElse("");
|
|
||||||
if (!docUrl.isEmpty()) {
|
|
||||||
abandonMessage = abandonMessage.replaceAll("\\$\\{URL\\}", docUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return abandonMessage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Schedule> getSchedule() {
|
public Optional<Schedule> getSchedule() {
|
||||||
@@ -80,6 +74,8 @@ public class ChangeCleanupConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getAbandonMessage() {
|
public String getAbandonMessage() {
|
||||||
return abandonMessage;
|
String docUrl =
|
||||||
|
urlFormatter.get().getDocUrl("user-change-cleanup.html", "auto-abandon").orElse("");
|
||||||
|
return docUrl.isEmpty() ? abandonMessage : abandonMessage.replace("${URL}", docUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,16 +40,15 @@ public interface UrlFormatter {
|
|||||||
Optional<String> getWebUrl();
|
Optional<String> getWebUrl();
|
||||||
|
|
||||||
/** Returns the URL for viewing a change. */
|
/** Returns the URL for viewing a change. */
|
||||||
default Optional<String> getChangeViewUrl(@Nullable Project.NameKey project, Change.Id id) {
|
default Optional<String> getChangeViewUrl(Project.NameKey project, Change.Id id) {
|
||||||
|
|
||||||
// In the PolyGerrit URL (contrary to REST URLs) there is no need to URL-escape strings, since
|
// In the PolyGerrit URL (contrary to REST URLs) there is no need to URL-escape strings, since
|
||||||
// the /+/ separator unambiguously defines how to parse the path.
|
// the /+/ separator unambiguously defines how to parse the path.
|
||||||
return getWebUrl()
|
return getWebUrl().map(url -> url + "c/" + project.get() + "/+/" + id.get());
|
||||||
.map(url -> url + "c/" + (project != null ? project.get() + "/+/" : "") + id.get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a URL pointing to a section of the settings page. */
|
/** Returns a URL pointing to a section of the settings page. */
|
||||||
default Optional<String> getSettingsUrl(String section) {
|
default Optional<String> getSettingsUrl(@Nullable String section) {
|
||||||
return getWebUrl()
|
return getWebUrl()
|
||||||
.map(url -> url + "settings" + (Strings.isNullOrEmpty(section) ? "" : "#" + section));
|
.map(url -> url + "settings" + (Strings.isNullOrEmpty(section) ? "" : "#" + section));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.google.gerrit.common.data.LabelType;
|
|||||||
import com.google.gerrit.common.data.LabelTypes;
|
import com.google.gerrit.common.data.LabelTypes;
|
||||||
import com.google.gerrit.common.data.SubmitRecord;
|
import com.google.gerrit.common.data.SubmitRecord;
|
||||||
import com.google.gerrit.common.data.SubmitRequirement;
|
import com.google.gerrit.common.data.SubmitRequirement;
|
||||||
|
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||||
import com.google.gerrit.index.IndexConfig;
|
import com.google.gerrit.index.IndexConfig;
|
||||||
import com.google.gerrit.reviewdb.client.Account;
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
import com.google.gerrit.reviewdb.client.Branch;
|
import com.google.gerrit.reviewdb.client.Branch;
|
||||||
@@ -83,7 +84,7 @@ public class EventFactory {
|
|||||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||||
|
|
||||||
private final AccountCache accountCache;
|
private final AccountCache accountCache;
|
||||||
private final UrlFormatter urlFormatter;
|
private final DynamicItem<UrlFormatter> urlFormatter;
|
||||||
private final Emails emails;
|
private final Emails emails;
|
||||||
private final PatchListCache patchListCache;
|
private final PatchListCache patchListCache;
|
||||||
private final Provider<PersonIdent> myIdent;
|
private final Provider<PersonIdent> myIdent;
|
||||||
@@ -97,7 +98,7 @@ public class EventFactory {
|
|||||||
EventFactory(
|
EventFactory(
|
||||||
AccountCache accountCache,
|
AccountCache accountCache,
|
||||||
Emails emails,
|
Emails emails,
|
||||||
UrlFormatter urlFormatter,
|
DynamicItem<UrlFormatter> urlFormatter,
|
||||||
PatchListCache patchListCache,
|
PatchListCache patchListCache,
|
||||||
@GerritPersonIdent Provider<PersonIdent> myIdent,
|
@GerritPersonIdent Provider<PersonIdent> myIdent,
|
||||||
ChangeData.Factory changeDataFactory,
|
ChangeData.Factory changeDataFactory,
|
||||||
@@ -634,7 +635,7 @@ public class EventFactory {
|
|||||||
/** Get a link to the change; null if the server doesn't know its own address. */
|
/** Get a link to the change; null if the server doesn't know its own address. */
|
||||||
private String getChangeUrl(Change change) {
|
private String getChangeUrl(Change change) {
|
||||||
if (change != null) {
|
if (change != null) {
|
||||||
return urlFormatter.getChangeViewUrl(change.getProject(), change.getId()).orElse(null);
|
return urlFormatter.get().getChangeViewUrl(change.getProject(), change.getId()).orElse(null);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ package com.google.gerrit.server.git;
|
|||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
|
||||||
|
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||||
import com.google.gerrit.reviewdb.client.Change;
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
import com.google.gerrit.server.config.UrlFormatter;
|
import com.google.gerrit.server.config.UrlFormatter;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
@@ -28,10 +29,10 @@ public class DefaultChangeReportFormatter implements ChangeReportFormatter {
|
|||||||
private static final int SUBJECT_CROP_RANGE = 10;
|
private static final int SUBJECT_CROP_RANGE = 10;
|
||||||
private static final String NEW_CHANGE_INDICATOR = " [NEW]";
|
private static final String NEW_CHANGE_INDICATOR = " [NEW]";
|
||||||
|
|
||||||
private final UrlFormatter urlFormatter;
|
private final DynamicItem<UrlFormatter> urlFormatter;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
DefaultChangeReportFormatter(UrlFormatter urlFormatter) {
|
DefaultChangeReportFormatter(DynamicItem<UrlFormatter> urlFormatter) {
|
||||||
this.urlFormatter = urlFormatter;
|
this.urlFormatter = urlFormatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +51,10 @@ public class DefaultChangeReportFormatter implements ChangeReportFormatter {
|
|||||||
Change c = input.change();
|
Change c = input.change();
|
||||||
return String.format(
|
return String.format(
|
||||||
"change %s closed",
|
"change %s closed",
|
||||||
urlFormatter.getChangeViewUrl(c.getProject(), c.getId()).orElse(c.getId().toString()));
|
urlFormatter
|
||||||
|
.get()
|
||||||
|
.getChangeViewUrl(c.getProject(), c.getId())
|
||||||
|
.orElse(c.getId().toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String cropSubject(String subject) {
|
protected String cropSubject(String subject) {
|
||||||
@@ -70,7 +74,7 @@ public class DefaultChangeReportFormatter implements ChangeReportFormatter {
|
|||||||
|
|
||||||
protected String formatChangeUrl(Input input) {
|
protected String formatChangeUrl(Input input) {
|
||||||
Change c = input.change();
|
Change c = input.change();
|
||||||
Optional<String> changeUrl = urlFormatter.getChangeViewUrl(c.getProject(), c.getId());
|
Optional<String> changeUrl = urlFormatter.get().getChangeViewUrl(c.getProject(), c.getId());
|
||||||
checkState(changeUrl.isPresent());
|
checkState(changeUrl.isPresent());
|
||||||
|
|
||||||
StringBuilder m =
|
StringBuilder m =
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import com.google.common.collect.Sets;
|
|||||||
import com.google.common.flogger.FluentLogger;
|
import com.google.common.flogger.FluentLogger;
|
||||||
import com.google.gerrit.common.FooterConstants;
|
import com.google.gerrit.common.FooterConstants;
|
||||||
import com.google.gerrit.common.data.LabelType;
|
import com.google.gerrit.common.data.LabelType;
|
||||||
|
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
import com.google.gerrit.extensions.restapi.MergeConflictException;
|
import com.google.gerrit.extensions.restapi.MergeConflictException;
|
||||||
@@ -159,7 +160,7 @@ public class MergeUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final IdentifiedUser.GenericFactory identifiedUserFactory;
|
private final IdentifiedUser.GenericFactory identifiedUserFactory;
|
||||||
private final UrlFormatter urlFormatter;
|
private final DynamicItem<UrlFormatter> urlFormatter;
|
||||||
private final ApprovalsUtil approvalsUtil;
|
private final ApprovalsUtil approvalsUtil;
|
||||||
private final ProjectState project;
|
private final ProjectState project;
|
||||||
private final boolean useContentMerge;
|
private final boolean useContentMerge;
|
||||||
@@ -170,7 +171,7 @@ public class MergeUtil {
|
|||||||
MergeUtil(
|
MergeUtil(
|
||||||
@GerritServerConfig Config serverConfig,
|
@GerritServerConfig Config serverConfig,
|
||||||
IdentifiedUser.GenericFactory identifiedUserFactory,
|
IdentifiedUser.GenericFactory identifiedUserFactory,
|
||||||
UrlFormatter urlFormatter,
|
DynamicItem<UrlFormatter> urlFormatter,
|
||||||
ApprovalsUtil approvalsUtil,
|
ApprovalsUtil approvalsUtil,
|
||||||
PluggableCommitMessageGenerator commitMessageGenerator,
|
PluggableCommitMessageGenerator commitMessageGenerator,
|
||||||
@Assisted ProjectState project) {
|
@Assisted ProjectState project) {
|
||||||
@@ -188,7 +189,7 @@ public class MergeUtil {
|
|||||||
MergeUtil(
|
MergeUtil(
|
||||||
@GerritServerConfig Config serverConfig,
|
@GerritServerConfig Config serverConfig,
|
||||||
IdentifiedUser.GenericFactory identifiedUserFactory,
|
IdentifiedUser.GenericFactory identifiedUserFactory,
|
||||||
UrlFormatter urlFormatter,
|
DynamicItem<UrlFormatter> urlFormatter,
|
||||||
ApprovalsUtil approvalsUtil,
|
ApprovalsUtil approvalsUtil,
|
||||||
@Assisted ProjectState project,
|
@Assisted ProjectState project,
|
||||||
PluggableCommitMessageGenerator commitMessageGenerator,
|
PluggableCommitMessageGenerator commitMessageGenerator,
|
||||||
@@ -482,7 +483,7 @@ public class MergeUtil {
|
|||||||
msgbuf.append('\n');
|
msgbuf.append('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<String> url = urlFormatter.getChangeViewUrl(null, c.getId());
|
Optional<String> url = urlFormatter.get().getChangeViewUrl(c.getProject(), c.getId());
|
||||||
if (url.isPresent()) {
|
if (url.isPresent()) {
|
||||||
if (!contains(footers, FooterConstants.REVIEWED_ON, url.get())) {
|
if (!contains(footers, FooterConstants.REVIEWED_ON, url.get())) {
|
||||||
msgbuf
|
msgbuf
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.google.common.base.Strings;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.flogger.FluentLogger;
|
import com.google.common.flogger.FluentLogger;
|
||||||
import com.google.gerrit.extensions.client.Side;
|
import com.google.gerrit.extensions.client.Side;
|
||||||
|
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||||
import com.google.gerrit.extensions.registration.Extension;
|
import com.google.gerrit.extensions.registration.Extension;
|
||||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||||
@@ -96,7 +97,7 @@ public class MailProcessor {
|
|||||||
private final CommentAdded commentAdded;
|
private final CommentAdded commentAdded;
|
||||||
private final ApprovalsUtil approvalsUtil;
|
private final ApprovalsUtil approvalsUtil;
|
||||||
private final AccountCache accountCache;
|
private final AccountCache accountCache;
|
||||||
private final UrlFormatter urlFormatter;
|
private final DynamicItem<UrlFormatter> urlFormatter;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public MailProcessor(
|
public MailProcessor(
|
||||||
@@ -114,7 +115,7 @@ public class MailProcessor {
|
|||||||
ApprovalsUtil approvalsUtil,
|
ApprovalsUtil approvalsUtil,
|
||||||
CommentAdded commentAdded,
|
CommentAdded commentAdded,
|
||||||
AccountCache accountCache,
|
AccountCache accountCache,
|
||||||
UrlFormatter urlFormatter) {
|
DynamicItem<UrlFormatter> urlFormatter) {
|
||||||
this.emails = emails;
|
this.emails = emails;
|
||||||
this.emailRejectionSender = emailRejectionSender;
|
this.emailRejectionSender = emailRejectionSender;
|
||||||
this.retryHelper = retryHelper;
|
this.retryHelper = retryHelper;
|
||||||
@@ -240,7 +241,10 @@ public class MailProcessor {
|
|||||||
// If URL is not defined, we won't be able to parse line comments. We still attempt to get the
|
// If URL is not defined, we won't be able to parse line comments. We still attempt to get the
|
||||||
// other ones.
|
// other ones.
|
||||||
String changeUrl =
|
String changeUrl =
|
||||||
urlFormatter.getChangeViewUrl(cd.project(), cd.getId()).orElse("http://gerrit.invalid/");
|
urlFormatter
|
||||||
|
.get()
|
||||||
|
.getChangeViewUrl(cd.project(), cd.getId())
|
||||||
|
.orElse("http://gerrit.invalid/");
|
||||||
|
|
||||||
List<MailComment> parsedComments;
|
List<MailComment> parsedComments;
|
||||||
if (useHtmlParser(message)) {
|
if (useHtmlParser(message)) {
|
||||||
|
|||||||
@@ -219,7 +219,10 @@ public abstract class ChangeEmail extends NotificationEmail {
|
|||||||
/** Get a link to the change; null if the server doesn't know its own address. */
|
/** Get a link to the change; null if the server doesn't know its own address. */
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getChangeUrl() {
|
public String getChangeUrl() {
|
||||||
return args.urlFormatter.getChangeViewUrl(change.getProject(), change.getId()).orElse(null);
|
return args.urlFormatter
|
||||||
|
.get()
|
||||||
|
.getChangeViewUrl(change.getProject(), change.getId())
|
||||||
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getChangeMessageThreadId() {
|
public String getChangeMessageThreadId() {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
package com.google.gerrit.server.mail.send;
|
package com.google.gerrit.server.mail.send;
|
||||||
|
|
||||||
import com.google.gerrit.common.UsedAt;
|
import com.google.gerrit.common.UsedAt;
|
||||||
|
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||||
import com.google.gerrit.server.AnonymousUser;
|
import com.google.gerrit.server.AnonymousUser;
|
||||||
import com.google.gerrit.server.ApprovalsUtil;
|
import com.google.gerrit.server.ApprovalsUtil;
|
||||||
@@ -67,7 +68,7 @@ public class EmailArguments {
|
|||||||
final AnonymousUser anonymousUser;
|
final AnonymousUser anonymousUser;
|
||||||
final String anonymousCowardName;
|
final String anonymousCowardName;
|
||||||
final PersonIdent gerritPersonIdent;
|
final PersonIdent gerritPersonIdent;
|
||||||
final UrlFormatter urlFormatter;
|
final DynamicItem<UrlFormatter> urlFormatter;
|
||||||
final AllProjectsName allProjectsName;
|
final AllProjectsName allProjectsName;
|
||||||
final List<String> sshAddresses;
|
final List<String> sshAddresses;
|
||||||
final SitePaths site;
|
final SitePaths site;
|
||||||
@@ -100,7 +101,7 @@ public class EmailArguments {
|
|||||||
AnonymousUser anonymousUser,
|
AnonymousUser anonymousUser,
|
||||||
@AnonymousCowardName String anonymousCowardName,
|
@AnonymousCowardName String anonymousCowardName,
|
||||||
GerritPersonIdentProvider gerritPersonIdentProvider,
|
GerritPersonIdentProvider gerritPersonIdentProvider,
|
||||||
UrlFormatter urlFormatter,
|
DynamicItem<UrlFormatter> urlFormatter,
|
||||||
AllProjectsName allProjectsName,
|
AllProjectsName allProjectsName,
|
||||||
ChangeQueryBuilder queryBuilder,
|
ChangeQueryBuilder queryBuilder,
|
||||||
ChangeData.Factory changeDataFactory,
|
ChangeData.Factory changeDataFactory,
|
||||||
|
|||||||
@@ -292,7 +292,7 @@ public abstract class OutgoingEmail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getGerritUrl() {
|
public String getGerritUrl() {
|
||||||
return args.urlFormatter.getWebUrl().orElse(null);
|
return args.urlFormatter.get().getWebUrl().orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set a header in the outgoing message. */
|
/** Set a header in the outgoing message. */
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import static java.util.Objects.requireNonNull;
|
|||||||
import com.google.gerrit.common.data.ContributorAgreement;
|
import com.google.gerrit.common.data.ContributorAgreement;
|
||||||
import com.google.gerrit.common.data.PermissionRule;
|
import com.google.gerrit.common.data.PermissionRule;
|
||||||
import com.google.gerrit.common.data.PermissionRule.Action;
|
import com.google.gerrit.common.data.PermissionRule.Action;
|
||||||
|
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||||
import com.google.gerrit.extensions.restapi.AuthException;
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
import com.google.gerrit.metrics.Counter0;
|
import com.google.gerrit.metrics.Counter0;
|
||||||
import com.google.gerrit.metrics.Description;
|
import com.google.gerrit.metrics.Description;
|
||||||
@@ -43,7 +44,7 @@ import java.util.regex.PatternSyntaxException;
|
|||||||
@Singleton
|
@Singleton
|
||||||
public class ContributorAgreementsChecker {
|
public class ContributorAgreementsChecker {
|
||||||
|
|
||||||
private final UrlFormatter urlFormatter;
|
private final DynamicItem<UrlFormatter> urlFormatter;
|
||||||
private final ProjectCache projectCache;
|
private final ProjectCache projectCache;
|
||||||
private final Metrics metrics;
|
private final Metrics metrics;
|
||||||
|
|
||||||
@@ -62,7 +63,7 @@ public class ContributorAgreementsChecker {
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ContributorAgreementsChecker(
|
ContributorAgreementsChecker(
|
||||||
UrlFormatter urlFormatter, ProjectCache projectCache, Metrics metrics) {
|
DynamicItem<UrlFormatter> urlFormatter, ProjectCache projectCache, Metrics metrics) {
|
||||||
this.urlFormatter = urlFormatter;
|
this.urlFormatter = urlFormatter;
|
||||||
this.projectCache = projectCache;
|
this.projectCache = projectCache;
|
||||||
this.metrics = metrics;
|
this.metrics = metrics;
|
||||||
@@ -129,7 +130,7 @@ public class ContributorAgreementsChecker {
|
|||||||
.append(iUser.getAccountId())
|
.append(iUser.getAccountId())
|
||||||
.append(")");
|
.append(")");
|
||||||
|
|
||||||
msg.append(urlFormatter.getSettingsUrl("Agreements").orElse(""));
|
msg.append(urlFormatter.get().getSettingsUrl("Agreements").orElse(""));
|
||||||
throw new AuthException(msg.toString());
|
throw new AuthException(msg.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
|||||||
import com.google.gerrit.common.data.GarbageCollectionResult;
|
import com.google.gerrit.common.data.GarbageCollectionResult;
|
||||||
import com.google.gerrit.common.data.GlobalCapability;
|
import com.google.gerrit.common.data.GlobalCapability;
|
||||||
import com.google.gerrit.extensions.annotations.RequiresCapability;
|
import com.google.gerrit.extensions.annotations.RequiresCapability;
|
||||||
|
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||||
import com.google.gerrit.extensions.restapi.BinaryResult;
|
import com.google.gerrit.extensions.restapi.BinaryResult;
|
||||||
import com.google.gerrit.extensions.restapi.Response;
|
import com.google.gerrit.extensions.restapi.Response;
|
||||||
import com.google.gerrit.extensions.restapi.RestModifyView;
|
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||||
@@ -55,14 +56,14 @@ public class GarbageCollect
|
|||||||
private final boolean canGC;
|
private final boolean canGC;
|
||||||
private final GarbageCollection.Factory garbageCollectionFactory;
|
private final GarbageCollection.Factory garbageCollectionFactory;
|
||||||
private final WorkQueue workQueue;
|
private final WorkQueue workQueue;
|
||||||
private final UrlFormatter urlFormatter;
|
private final DynamicItem<UrlFormatter> urlFormatter;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
GarbageCollect(
|
GarbageCollect(
|
||||||
GitRepositoryManager repoManager,
|
GitRepositoryManager repoManager,
|
||||||
GarbageCollection.Factory garbageCollectionFactory,
|
GarbageCollection.Factory garbageCollectionFactory,
|
||||||
WorkQueue workQueue,
|
WorkQueue workQueue,
|
||||||
UrlFormatter urlFormatter) {
|
DynamicItem<UrlFormatter> urlFormatter) {
|
||||||
this.workQueue = workQueue;
|
this.workQueue = workQueue;
|
||||||
this.urlFormatter = urlFormatter;
|
this.urlFormatter = urlFormatter;
|
||||||
this.canGC = repoManager instanceof LocalDiskRepositoryManager;
|
this.canGC = repoManager instanceof LocalDiskRepositoryManager;
|
||||||
@@ -99,7 +100,9 @@ public class GarbageCollect
|
|||||||
WorkQueue.Task<Void> task = (WorkQueue.Task<Void>) workQueue.getDefaultQueue().submit(job);
|
WorkQueue.Task<Void> task = (WorkQueue.Task<Void>) workQueue.getDefaultQueue().submit(job);
|
||||||
|
|
||||||
Optional<String> url =
|
Optional<String> url =
|
||||||
urlFormatter.getRestUrl("a/config/server/tasks/" + HexFormat.fromInt(task.getTaskId()));
|
urlFormatter
|
||||||
|
.get()
|
||||||
|
.getRestUrl("a/config/server/tasks/" + HexFormat.fromInt(task.getTaskId()));
|
||||||
// We're in a HTTP handler, so must be present.
|
// We're in a HTTP handler, so must be present.
|
||||||
checkState(url.isPresent());
|
checkState(url.isPresent());
|
||||||
return Response.accepted(url.get());
|
return Response.accepted(url.get());
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
|||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
import com.google.gerrit.server.CurrentUser;
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.change.AbandonUtil;
|
import com.google.gerrit.server.change.AbandonUtil;
|
||||||
|
import com.google.gerrit.server.config.ChangeCleanupConfig;
|
||||||
import com.google.gerrit.server.query.change.ChangeData;
|
import com.google.gerrit.server.query.change.ChangeData;
|
||||||
import com.google.gerrit.testing.TestTimeUtil;
|
import com.google.gerrit.testing.TestTimeUtil;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
@@ -46,6 +47,7 @@ import org.junit.Test;
|
|||||||
public class AbandonIT extends AbstractDaemonTest {
|
public class AbandonIT extends AbstractDaemonTest {
|
||||||
@Inject private AbandonUtil abandonUtil;
|
@Inject private AbandonUtil abandonUtil;
|
||||||
@Inject private RequestScopeOperations requestScopeOperations;
|
@Inject private RequestScopeOperations requestScopeOperations;
|
||||||
|
@Inject private ChangeCleanupConfig cleanupConfig;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void abandon() throws Exception {
|
public void abandon() throws Exception {
|
||||||
@@ -124,6 +126,31 @@ public class AbandonIT extends AbstractDaemonTest {
|
|||||||
assertThat(toChangeNumbers(query("is:abandoned"))).containsExactly(id1, id2);
|
assertThat(toChangeNumbers(query("is:abandoned"))).containsExactly(id1, id2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void changeCleanupConfigDefaultAbandonMessage() throws Exception {
|
||||||
|
assertThat(cleanupConfig.getAbandonMessage())
|
||||||
|
.startsWith(
|
||||||
|
"Auto-Abandoned due to inactivity, see "
|
||||||
|
+ canonicalWebUrl.get()
|
||||||
|
+ "Documentation/user-change-cleanup.html#auto-abandon");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@GerritConfig(name = "changeCleanup.abandonMessage", value = "XX ${URL} XX")
|
||||||
|
public void changeCleanupConfigCustomAbandonMessageWithUrlReplacement() throws Exception {
|
||||||
|
assertThat(cleanupConfig.getAbandonMessage())
|
||||||
|
.isEqualTo(
|
||||||
|
"XX "
|
||||||
|
+ canonicalWebUrl.get()
|
||||||
|
+ "Documentation/user-change-cleanup.html#auto-abandon XX");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@GerritConfig(name = "changeCleanup.abandonMessage", value = "XX YYY XX")
|
||||||
|
public void changeCleanupConfigCustomAbandonMessageWithoutUrlReplacement() throws Exception {
|
||||||
|
assertThat(cleanupConfig.getAbandonMessage()).isEqualTo("XX YYY XX");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void abandonNotAllowedWithoutPermission() throws Exception {
|
public void abandonNotAllowedWithoutPermission() throws Exception {
|
||||||
PushOneCommit.Result r = createChange();
|
PushOneCommit.Result r = createChange();
|
||||||
|
|||||||
@@ -2671,7 +2671,12 @@ public class ChangeIT extends AbstractDaemonTest {
|
|||||||
List<String> expectedFooters =
|
List<String> expectedFooters =
|
||||||
Arrays.asList(
|
Arrays.asList(
|
||||||
"Change-Id: " + r2.getChangeId(),
|
"Change-Id: " + r2.getChangeId(),
|
||||||
"Reviewed-on: " + canonicalWebUrl.get() + "c/" + r2.getChange().getId(),
|
"Reviewed-on: "
|
||||||
|
+ canonicalWebUrl.get()
|
||||||
|
+ "c/"
|
||||||
|
+ project.get()
|
||||||
|
+ "/+/"
|
||||||
|
+ r2.getChange().getId(),
|
||||||
"Reviewed-by: Administrator <admin@example.com>",
|
"Reviewed-by: Administrator <admin@example.com>",
|
||||||
"Custom2: Administrator <admin@example.com>",
|
"Custom2: Administrator <admin@example.com>",
|
||||||
"Tested-by: Administrator <admin@example.com>");
|
"Tested-by: Administrator <admin@example.com>");
|
||||||
@@ -2706,7 +2711,12 @@ public class ChangeIT extends AbstractDaemonTest {
|
|||||||
List<String> expectedFooters =
|
List<String> expectedFooters =
|
||||||
Arrays.asList(
|
Arrays.asList(
|
||||||
"Change-Id: " + change.getChangeId(),
|
"Change-Id: " + change.getChangeId(),
|
||||||
"Reviewed-on: " + canonicalWebUrl.get() + "c/" + change.getChange().getId(),
|
"Reviewed-on: "
|
||||||
|
+ canonicalWebUrl.get()
|
||||||
|
+ "c/"
|
||||||
|
+ project.get()
|
||||||
|
+ "/+/"
|
||||||
|
+ change.getChange().getId(),
|
||||||
"Custom: refs/heads/master");
|
"Custom: refs/heads/master");
|
||||||
assertThat(footers).containsExactlyElementsIn(expectedFooters);
|
assertThat(footers).containsExactlyElementsIn(expectedFooters);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class ElasticContainer extends ElasticsearchContainer {
|
|||||||
private static String getImageName(ElasticVersion version) {
|
private static String getImageName(ElasticVersion version) {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case V5_6:
|
case V5_6:
|
||||||
return "docker.elastic.co/elasticsearch/elasticsearch:5.6.14";
|
return "docker.elastic.co/elasticsearch/elasticsearch:5.6.15";
|
||||||
case V6_2:
|
case V6_2:
|
||||||
return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.4";
|
return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.4";
|
||||||
case V6_3:
|
case V6_3:
|
||||||
@@ -47,7 +47,7 @@ public class ElasticContainer extends ElasticsearchContainer {
|
|||||||
case V6_5:
|
case V6_5:
|
||||||
return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.5.4";
|
return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.5.4";
|
||||||
case V6_6:
|
case V6_6:
|
||||||
return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.6.0";
|
return "docker.elastic.co/elasticsearch/elasticsearch-oss:6.6.1";
|
||||||
case V7_0:
|
case V7_0:
|
||||||
return "docker.elastic.co/elasticsearch/elasticsearch-oss:7.0.0-beta1";
|
return "docker.elastic.co/elasticsearch/elasticsearch-oss:7.0.0-beta1";
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user