Merge branch 'stable-2.12' * stable-2.12: Add 2.12 release notes to release notes index Make email validation case insensitive Add tooltip with subject message in related changes tab Correct timezone logged for DST changes Add hmac-sha2-256 and hmac-sha2-512 as MACs for sshd Fix double slash on URL when switching account. commit-msg: Do not add Change-Id to temp commits Use image instead of Unicode Character for Copy Button Change-Id: I6dc9c93e0962a19e2c32dbcf86f0389b5e2a7acc
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt index db52a1b..359f281 100644 --- a/Documentation/config-gerrit.txt +++ b/Documentation/config-gerrit.txt
@@ -3515,7 +3515,8 @@ are enabled in addition to the default MACs, MAC names starting with `-` are removed from the default MACs. + -Supported MACs: hmac-md5, hmac-md5-96, hmac-sha1, hmac-sha1-96. +Supported MACs: hmac-md5, hmac-md5-96, hmac-sha1, hmac-sha1-96, +hmac-sha2-256, hmac-sha2-512. + By default, all supported MACs are available.
diff --git a/ReleaseNotes/index.txt b/ReleaseNotes/index.txt index e1831ad..05368c8 100644 --- a/ReleaseNotes/index.txt +++ b/ReleaseNotes/index.txt
@@ -1,6 +1,11 @@ Gerrit Code Review - Release Notes ================================== +[[2_12]] +Version 2.12.x +-------------- +* link:ReleaseNotes-2.12.html[2.12] + [[2_11]] Version 2.11.x --------------
diff --git a/gerrit-gwtexpui/BUCK b/gerrit-gwtexpui/BUCK index 189445a..4b2cb03 100644 --- a/gerrit-gwtexpui/BUCK +++ b/gerrit-gwtexpui/BUCK
@@ -7,6 +7,7 @@ resources = [ SRC + 'clippy/client/clippy.css', SRC + 'clippy/client/clippy.swf', + SRC + 'clippy/client/clipboard-16.png', SRC + 'clippy/client/CopyableLabelText.properties', ], provided_deps = ['//lib/gwt:user'], @@ -14,6 +15,7 @@ ':SafeHtml', ':UserAgent', '//lib:LICENSE-clippy', + '//lib:LICENSE-drifty', ], visibility = ['PUBLIC'], )
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/ClippyResources.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/ClippyResources.java index dfa7679..dd3cc18 100644 --- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/ClippyResources.java +++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/ClippyResources.java
@@ -18,6 +18,7 @@ import com.google.gwt.resources.client.ClientBundle; import com.google.gwt.resources.client.DataResource; import com.google.gwt.resources.client.DataResource.DoNotEmbed; +import com.google.gwt.resources.client.ImageResource; public interface ClippyResources extends ClientBundle { public static final ClippyResources I = GWT.create(ClippyResources.class); @@ -28,4 +29,7 @@ @Source("clippy.swf") @DoNotEmbed DataResource swf(); + + @Source("clipboard-16.png") + ImageResource clipboard(); }
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/CopyableLabel.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/CopyableLabel.java index 4b6e7e4..8d54b2f 100644 --- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/CopyableLabel.java +++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/CopyableLabel.java
@@ -119,7 +119,12 @@ } if (UserAgent.hasJavaScriptClipboard()) { - copier = new Button("📋"); // CLIPBOARD + copier = new Button(new SafeHtmlBuilder() + .openElement("img") + .setAttribute("src", ClippyResources.I.clipboard().getSafeUri().asString()) + .setWidth(14) + .setHeight(14) + .closeSelf()); copier.setStyleName(ClippyResources.I.css().copier()); Tooltip.addStyle(copier); Tooltip.setLabel(copier, CopyableLabelText.I.tooltip());
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/clipboard-16.png b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/clipboard-16.png new file mode 100644 index 0000000..9c6e10a --- /dev/null +++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/clipboard-16.png Binary files differ
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/UserPopupPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/UserPopupPanel.java index 00036a8..0924796 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/UserPopupPanel.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/UserPopupPanel.java
@@ -54,7 +54,7 @@ switchAccount.setHref(Gerrit.info().auth().switchAccountUrl()); } else if (Gerrit.info().auth().isDev() || Gerrit.info().auth().isOpenId()) { - switchAccount.setHref(Gerrit.selfRedirect("/login/")); + switchAccount.setHref(Gerrit.selfRedirect("/login")); } else { switchAccount.removeFromParent(); switchAccount = null;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java index 525f5a9..23959e7 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChangesTab.java
@@ -292,6 +292,7 @@ if (url.startsWith("#")) { sb.setAttribute("onclick", OPEN); } + sb.setAttribute("title", info.commit().subject()); if (showProjects) { sb.append(info.project()).append(": "); }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java index 9e5ff12..2768733 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
@@ -196,7 +196,8 @@ private final GroupBackend groupBackend; private final String anonymousCowardName; private final Boolean disableReverseDnsLookup; - private final Set<String> validEmails = Sets.newHashSetWithExpectedSize(4); + private final Set<String> validEmails = + Sets.newTreeSet(String.CASE_INSENSITIVE_ORDER); @Nullable private final Provider<SocketAddress> remotePeerProvider; @@ -284,7 +285,7 @@ validEmails.add(email); return true; } else if (invalidEmails == null) { - invalidEmails = Sets.newHashSetWithExpectedSize(4); + invalidEmails = Sets.newTreeSet(String.CASE_INSENSITIVE_ORDER); } invalidEmails.add(email); return false;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AbstractRealm.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AbstractRealm.java index 34f83f7..30420e0 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AbstractRealm.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AbstractRealm.java
@@ -25,7 +25,6 @@ import java.util.Collection; import java.util.HashSet; -import java.util.Objects; import java.util.Set; /** Basic implementation of {@link Realm}. */ @@ -57,7 +56,7 @@ @Override public boolean hasEmailAddress(IdentifiedUser user, String email) { for (AccountExternalId ext : user.state().getExternalIds()) { - if (Objects.equals(ext.getEmailAddress(), email)) { + if (email != null && email.equalsIgnoreCase(ext.getEmailAddress())) { return true; } }
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg b/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg index be88bd4..6988459 100644 --- a/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg +++ b/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg
@@ -38,6 +38,12 @@ return fi + # Do not add Change-Id to temp commits + if echo "$clean_message" | head -1 | grep -q '^\(fixup\|squash\)!' + then + return + fi + if test "false" = "`git config --bool --get gerrit.createChangeId`" then return
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/IdentifiedUserTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/IdentifiedUserTest.java new file mode 100644 index 0000000..039871e --- /dev/null +++ b/gerrit-server/src/test/java/com/google/gerrit/server/IdentifiedUserTest.java
@@ -0,0 +1,131 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.inject.Scopes.SINGLETON; + +import com.google.gerrit.common.TimeUtil; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.server.account.AccountCache; +import com.google.gerrit.server.account.CapabilityControl; +import com.google.gerrit.server.account.FakeRealm; +import com.google.gerrit.server.account.GroupBackend; +import com.google.gerrit.server.account.Realm; +import com.google.gerrit.server.config.AnonymousCowardName; +import com.google.gerrit.server.config.AnonymousCowardNameProvider; +import com.google.gerrit.server.config.CanonicalWebUrl; +import com.google.gerrit.server.config.DisableReverseDnsLookup; +import com.google.gerrit.server.config.GerritServerConfig; +import com.google.gerrit.server.group.SystemGroupBackend; +import com.google.gerrit.testutil.ConfigSuite; +import com.google.gerrit.testutil.FakeAccountCache; +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.util.Providers; + +import org.eclipse.jgit.lib.Config; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +@RunWith(ConfigSuite.class) +public class IdentifiedUserTest { + @ConfigSuite.Parameter + public Config config; + + private IdentifiedUser identifiedUser; + + @Inject + private IdentifiedUser.GenericFactory identifiedUserFactory; + + private static final String[] TEST_CASES = { + "", + "FirstName.LastName@Corporation.com", + "!#$%&'+-/=.?^`{|}~@[IPv6:0123:4567:89AB:CDEF:0123:4567:89AB:CDEF]" + }; + + @Before + public void setUp() throws Exception { + final FakeAccountCache accountCache = new FakeAccountCache(); + final Realm mockRealm = new FakeRealm() { + HashSet<String> emails = new HashSet<>(Arrays.asList(TEST_CASES)); + + @Override + public boolean hasEmailAddress(IdentifiedUser who, String email) { + return emails.contains(email); + } + + @Override + public Set<String> getEmailAddresses(IdentifiedUser who) { + return emails; + } + }; + + AbstractModule mod = new AbstractModule() { + @Override + protected void configure() { + bind(Boolean.class).annotatedWith(DisableReverseDnsLookup.class) + .toInstance(Boolean.FALSE); + bind(Config.class).annotatedWith(GerritServerConfig.class).toInstance(config); + bind(String.class).annotatedWith(AnonymousCowardName.class) + .toProvider(AnonymousCowardNameProvider.class); + bind(String.class).annotatedWith(CanonicalWebUrl.class) + .toInstance("http://localhost:8080/"); + bind(AccountCache.class).toInstance(accountCache); + bind(GroupBackend.class).to(SystemGroupBackend.class).in(SINGLETON); + bind(CapabilityControl.Factory.class) + .toProvider(Providers.<CapabilityControl.Factory>of(null)); + bind(Realm.class).toInstance(mockRealm); + + } + }; + + Injector injector = Guice.createInjector(mod); + injector.injectMembers(this); + + Account account = new Account(new Account.Id(1), TimeUtil.nowTs()); + Account.Id ownerId = account.getId(); + + identifiedUser = identifiedUserFactory.create(ownerId); + + /* Trigger identifiedUser to load the email addresses from mockRealm */ + identifiedUser.getEmailAddresses(); + } + + @Test + public void testEmailsExistence() { + assertThat(identifiedUser.hasEmailAddress(TEST_CASES[0])).isTrue(); + assertThat(identifiedUser.hasEmailAddress(TEST_CASES[1].toLowerCase())).isTrue(); + assertThat(identifiedUser.hasEmailAddress(TEST_CASES[1])).isTrue(); + assertThat(identifiedUser.hasEmailAddress(TEST_CASES[1].toUpperCase())).isTrue(); + /* assert again to test cached email address by IdentifiedUser.validEmails */ + assertThat(identifiedUser.hasEmailAddress(TEST_CASES[1])).isTrue(); + + assertThat(identifiedUser.hasEmailAddress(TEST_CASES[2])).isTrue(); + assertThat(identifiedUser.hasEmailAddress(TEST_CASES[2].toLowerCase())).isTrue(); + + + assertThat(identifiedUser.hasEmailAddress("non-exist@email.com")).isFalse(); + /* assert again to test cached email address by IdentifiedUser.invalidEmails */ + assertThat(identifiedUser.hasEmailAddress("non-exist@email.com")).isFalse(); + } +}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java index 7ca5d4d..18e950a 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
@@ -83,6 +83,8 @@ import org.apache.sshd.common.mac.HMACMD596; import org.apache.sshd.common.mac.HMACSHA1; import org.apache.sshd.common.mac.HMACSHA196; +import org.apache.sshd.common.mac.HMACSHA256; +import org.apache.sshd.common.mac.HMACSHA512; import org.apache.sshd.common.random.BouncyCastleRandom; import org.apache.sshd.common.random.JceRandom; import org.apache.sshd.common.random.SingletonRandomFactory; @@ -552,9 +554,13 @@ } private void initMacs(final Config cfg) { - setMacFactories(filter(cfg, "mac", new HMACMD5.Factory(), - new HMACSHA1.Factory(), new HMACMD596.Factory(), - new HMACSHA196.Factory())); + setMacFactories(filter(cfg, "mac", + new HMACMD5.Factory(), + new HMACSHA1.Factory(), + new HMACMD596.Factory(), + new HMACSHA196.Factory(), + new HMACSHA256.Factory(), + new HMACSHA512.Factory())); } @SafeVarargs
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLogLayout.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLogLayout.java index 2bed29d..541081e 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLogLayout.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLogLayout.java
@@ -20,7 +20,6 @@ import java.text.SimpleDateFormat; import java.util.Calendar; -import java.util.Date; import java.util.TimeZone; public final class SshLogLayout extends Layout { @@ -36,15 +35,15 @@ private final Calendar calendar; private long lastTimeMillis; private final char[] lastTimeString = new char[20]; - private final char[] timeZone; + private final SimpleDateFormat tzFormat; + private char[] timeZone; public SshLogLayout() { final TimeZone tz = TimeZone.getDefault(); calendar = Calendar.getInstance(tz); - final SimpleDateFormat sdf = new SimpleDateFormat("Z"); - sdf.setTimeZone(tz); - timeZone = sdf.format(new Date()).toCharArray(); + tzFormat = new SimpleDateFormat("Z"); + tzFormat.setTimeZone(tz); } @Override @@ -53,8 +52,6 @@ buf.append('['); formatDate(event.getTimeStamp(), buf); - buf.append(' '); - buf.append(timeZone); buf.append(']'); req(P_SESSION, buf, event); @@ -94,11 +91,14 @@ sbuf.append(','); sbuf.getChars(start, sbuf.length(), lastTimeString, 0); lastTimeMillis = rounded; + timeZone = tzFormat.format(calendar.getTime()).toCharArray(); } } else { sbuf.append(lastTimeString); } sbuf.append(String.format("%03d", millis)); + sbuf.append(' '); + sbuf.append(timeZone); } private String toTwoDigits(int input) {
diff --git a/lib/BUCK b/lib/BUCK index 73983da..a92f910 100644 --- a/lib/BUCK +++ b/lib/BUCK
@@ -12,6 +12,7 @@ define_license(name = 'clippy') define_license(name = 'codemirror') define_license(name = 'diffy') +define_license(name = 'drifty') define_license(name = 'freebie_application_icon_set') define_license(name = 'h2') define_license(name = 'jgit')
diff --git a/lib/LICENSE-drifty b/lib/LICENSE-drifty new file mode 100644 index 0000000..18ab118 --- /dev/null +++ b/lib/LICENSE-drifty
@@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Drifty (http://drifty.com/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.