Merge branch 'stable-2.13'

* stable-2.13:
  Support for at-sign (@) in usernames
  VersionedMetaData: Fix deletion of last file in branch
  WatchConfig.Accessor: Add method to delete all watches of an account

Change-Id: I2630ebc2d6bc7c5b68d40f8da2361ae08570790b
This commit is contained in:
David Pursehouse
2017-03-18 14:35:49 +09:00
4 changed files with 55 additions and 7 deletions

View File

@@ -98,6 +98,17 @@ public class GroupsIT extends AbstractDaemonTest {
assertMembers(g, u1, u2); assertMembers(g, u1, u2);
} }
@Test
public void addMembersWithAtSign() throws Exception {
String g = createGroup("users");
TestAccount u10 = accounts.create("u10", "u10@example.com", "Full Name 10");
TestAccount u11_at =
accounts.create("u11@something", "u11@example.com", "Full Name 11 With At");
TestAccount u11 = accounts.create("u11", "u11.another@example.com", "Full Name 11 Without At");
gApi.groups().id(g).addMembers(u10.username, u11_at.username);
assertMembers(g, u10, u11_at);
}
@Test @Test
public void includeRemoveGroup() throws Exception { public void includeRemoveGroup() throws Exception {
String p = createGroup("parent"); String p = createGroup("parent");

View File

@@ -23,26 +23,38 @@ import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit; import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.Sandboxed; import com.google.gerrit.acceptance.Sandboxed;
import com.google.gerrit.acceptance.TestAccount; import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.common.data.Permission; import com.google.gerrit.common.data.Permission;
import com.google.gerrit.extensions.api.changes.ReviewInput; import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.api.changes.StarsInput; import com.google.gerrit.extensions.api.changes.StarsInput;
import com.google.gerrit.extensions.common.GroupInfo; import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.account.WatchConfig;
import com.google.gerrit.server.account.WatchConfig.NotifyType; import com.google.gerrit.server.account.WatchConfig.NotifyType;
import com.google.gerrit.server.account.WatchConfig.ProjectWatchKey;
import com.google.gerrit.server.git.NotifyConfig; import com.google.gerrit.server.git.NotifyConfig;
import com.google.gerrit.server.git.ProjectConfig; import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.mail.Address; import com.google.gerrit.server.mail.Address;
import com.google.gerrit.testutil.FakeEmailSender.Message; import com.google.gerrit.testutil.FakeEmailSender.Message;
import com.google.inject.Inject;
import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.junit.TestRepository;
import org.junit.Test; import org.junit.Test;
@NoHttpd @NoHttpd
@Sandboxed @Sandboxed
public class ProjectWatchIT extends AbstractDaemonTest { public class ProjectWatchIT extends AbstractDaemonTest {
@Inject private WatchConfig.Accessor watchConfig;
@Test @Test
public void newPatchSetsNotifyConfig() throws Exception { public void newPatchSetsNotifyConfig() throws Exception {
Address addr = new Address("Watcher", "watcher@example.com"); Address addr = new Address("Watcher", "watcher@example.com");
@@ -480,4 +492,34 @@ public class ProjectWatchIT extends AbstractDaemonTest {
// assert email notification // assert email notification
assertThat(sender.getMessages()).isEmpty(); assertThat(sender.getMessages()).isEmpty();
} }
@Test
public void deleteAllProjectWatches() throws Exception {
Map<ProjectWatchKey, Set<NotifyType>> watches = new HashMap<>();
watches.put(ProjectWatchKey.create(project, "*"), ImmutableSet.of(NotifyType.ALL));
watchConfig.upsertProjectWatches(admin.getId(), watches);
assertThat(watchConfig.getProjectWatches(admin.getId())).isNotEmpty();
watchConfig.deleteAllProjectWatches(admin.getId());
assertThat(watchConfig.getProjectWatches(admin.getId())).isEmpty();
}
@Test
public void deleteAllProjectWatchesIfWatchConfigIsTheOnlyFileInUserBranch() throws Exception {
// Create account that has no files in its refs/users/ branch.
Account.Id id = new Account.Id(db.nextAccountId());
Account a = new Account(id, TimeUtil.nowTs());
db.accounts().insert(Collections.singleton(a));
// Add a project watch so that a watch.config file in the refs/users/ branch is created.
Map<ProjectWatchKey, Set<NotifyType>> watches = new HashMap<>();
watches.put(ProjectWatchKey.create(project, "*"), ImmutableSet.of(NotifyType.ALL));
watchConfig.upsertProjectWatches(id, watches);
assertThat(watchConfig.getProjectWatches(id)).isNotEmpty();
// Delete all project watches so that the watch.config file in the refs/users/ branch is
// deleted.
watchConfig.deleteAllProjectWatches(id);
assertThat(watchConfig.getProjectWatches(id)).isEmpty();
}
} }

View File

@@ -45,7 +45,7 @@ import java.sql.Timestamp;
*/ */
public final class Account { public final class Account {
public static final String USER_NAME_PATTERN_FIRST = "[a-zA-Z0-9]"; public static final String USER_NAME_PATTERN_FIRST = "[a-zA-Z0-9]";
public static final String USER_NAME_PATTERN_REST = "[a-zA-Z0-9._-]"; public static final String USER_NAME_PATTERN_REST = "[a-zA-Z0-9._@-]";
public static final String USER_NAME_PATTERN_LAST = "[a-zA-Z0-9]"; public static final String USER_NAME_PATTERN_LAST = "[a-zA-Z0-9]";
/** Regular expression that {@link #userName} must match. */ /** Regular expression that {@link #userName} must match. */

View File

@@ -281,12 +281,7 @@ public abstract class VersionedMetaData {
return; return;
} }
// Reuse tree from parent commit unless there are contents in newTree or ObjectId res = newTree.writeTree(inserter);
// there is no tree for a parent commit.
ObjectId res =
newTree.getEntryCount() != 0 || srcTree == null
? newTree.writeTree(inserter)
: srcTree.copy();
if (res.equals(srcTree) && !update.allowEmpty() && (commit.getTreeId() == null)) { if (res.equals(srcTree) && !update.allowEmpty() && (commit.getTreeId() == null)) {
// If there are no changes to the content, don't create the commit. // If there are no changes to the content, don't create the commit.
return; return;