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:
David Pursehouse
2019-02-26 21:17:53 +09:00
18 changed files with 124 additions and 53 deletions

View File

@@ -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"

View File

@@ -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() : ""));

View File

@@ -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();
}
} }

View File

@@ -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

View File

@@ -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);
} }
} }

View File

@@ -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));
} }

View File

@@ -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;
} }

View File

@@ -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 =

View File

@@ -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

View File

@@ -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)) {

View File

@@ -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() {

View File

@@ -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,

View File

@@ -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. */

View File

@@ -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());
} }
} }

View File

@@ -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());

View File

@@ -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();

View File

@@ -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);
} }

View File

@@ -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";
} }