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
This commit is contained in:
David Pursehouse 2015-11-12 09:39:52 -08:00
commit e132903bc8
16 changed files with 200 additions and 17 deletions

View File

@ -3515,7 +3515,8 @@ configuration file, one MAC per key. MAC names starting with `+`
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.

View File

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

View File

@ -7,6 +7,7 @@ gwt_module(
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 @@ gwt_module(
':SafeHtml',
':UserAgent',
'//lib:LICENSE-clippy',
'//lib:LICENSE-drifty',
],
visibility = ['PUBLIC'],
)

View File

@ -18,6 +18,7 @@ import com.google.gwt.core.client.GWT;
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 @@ public interface ClippyResources extends ClientBundle {
@Source("clippy.swf")
@DoNotEmbed
DataResource swf();
@Source("clipboard-16.png")
ImageResource clipboard();
}

View File

@ -119,7 +119,12 @@ public class CopyableLabel extends Composite implements HasText {
}
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());

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

View File

@ -54,7 +54,7 @@ public class UserPopupPanel extends PopupPanel {
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;

View File

@ -292,6 +292,7 @@ class RelatedChangesTab implements IsWidget {
if (url.startsWith("#")) {
sb.setAttribute("onclick", OPEN);
}
sb.setAttribute("title", info.commit().subject());
if (showProjects) {
sb.append(info.project()).append(": ");
}

View File

@ -196,7 +196,8 @@ public class IdentifiedUser extends CurrentUser {
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 @@ public class IdentifiedUser extends CurrentUser {
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;

View File

@ -25,7 +25,6 @@ import com.google.inject.Inject;
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 @@ public abstract class AbstractRealm implements Realm {
@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;
}
}

View File

@ -38,6 +38,12 @@ add_ChangeId() {
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

View File

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

View File

@ -83,6 +83,8 @@ import org.apache.sshd.common.mac.HMACMD5;
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 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
}
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

View File

@ -20,7 +20,6 @@ import org.eclipse.jgit.util.QuotedString;
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 @@ public final class SshLogLayout extends Layout {
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 @@ public final class SshLogLayout extends Layout {
buf.append('[');
formatDate(event.getTimeStamp(), buf);
buf.append(' ');
buf.append(timeZone);
buf.append(']');
req(P_SESSION, buf, event);
@ -94,11 +91,14 @@ public final class SshLogLayout extends Layout {
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) {

View File

@ -12,6 +12,7 @@ define_license(name = 'bouncycastle')
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')

21
lib/LICENSE-drifty Normal file
View File

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