Support fetch of refs/users/self from All-Users repository

Allow a user to fetch its refs/users/YY/XXXXXXX branch as
refs/users/self. The user branch contains the sharded account ID in
the ref name, but this is an implementation detail that should be
hidden from the user. On the other hand users should be able to access
their user branch easily.

Change-Id: I0f5a9f1456a86873ff91ad418aa60b1eee568109
Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
Edwin Kempin
2016-05-02 13:53:41 +02:00
parent 136aab1f0a
commit d3eb8fc937
5 changed files with 60 additions and 4 deletions

View File

@@ -17,6 +17,7 @@ package com.google.gerrit.acceptance.api.accounts;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assert_;
import static com.google.gerrit.acceptance.GitUtil.fetch;
import static com.google.gerrit.gpg.PublicKeyStore.REFS_GPG_KEYS;
import static com.google.gerrit.gpg.PublicKeyStore.keyToString;
import static com.google.gerrit.gpg.testutil.TestKeys.allValidKeys;
@@ -39,6 +40,7 @@ import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.extensions.api.accounts.EmailInput;
import com.google.gerrit.extensions.api.changes.AddReviewerInput;
import com.google.gerrit.extensions.api.changes.StarsInput;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.GpgKeyInfo;
@@ -53,6 +55,7 @@ import com.google.gerrit.gpg.server.GpgKeys;
import com.google.gerrit.gpg.testutil.TestKey;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountExternalId;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.testutil.ConfigSuite;
import com.google.gerrit.testutil.FakeEmailSender.Message;
@@ -62,6 +65,8 @@ import com.google.inject.Provider;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
@@ -354,6 +359,27 @@ public class AccountIT extends AbstractDaemonTest {
gApi.accounts().self().addEmail(input);
}
@Test
public void fetchUserBranch() throws Exception {
// change something in the user preferences to ensure that the user branch
// is created
GeneralPreferencesInfo input = new GeneralPreferencesInfo();
input.changesPerPage =
GeneralPreferencesInfo.defaults().changesPerPage + 10;
gApi.accounts().self().setPreferences(input);
TestRepository<InMemoryRepository> allUsersRepo = cloneProject(allUsers);
fetch(allUsersRepo, RefNames.refsUsers(admin.id) + ":userRef");
Ref userRef = allUsersRepo.getRepository().exactRef("userRef");
assertThat(userRef).isNotNull();
fetch(allUsersRepo, RefNames.REFS_USERS_SELF + ":userSelfRef");
Ref userSelfRef =
allUsersRepo.getRepository().getRefDatabase().exactRef("userSelfRef");
assertThat(userSelfRef).isNotNull();
assertThat(userSelfRef.getObjectId()).isEqualTo(userRef.getObjectId());
}
@Test
public void addGpgKey() throws Exception {
TestKey key = validKeyWithoutExpiration();

View File

@@ -33,6 +33,9 @@ public class RefNames {
/** Preference settings for a user {@code refs/users} */
public static final String REFS_USERS = "refs/users/";
/** Magic user branch in All-Users {@code refs/users/self} */
public static final String REFS_USERS_SELF = "refs/users/self";
/** Default user preference settings */
public static final String REFS_USERS_DEFAULT = RefNames.REFS_USERS + "default";

View File

@@ -29,6 +29,7 @@ import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.SymbolicRef;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.AbstractAdvertiseRefsHook;
import org.eclipse.jgit.transport.ServiceMayNotContinueException;
@@ -69,6 +70,18 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
}
public Map<String, Ref> filter(Map<String, Ref> refs, boolean filterTagsSeparately) {
if (projectCtl.getProjectState().isAllUsers()
&& projectCtl.getUser().isIdentifiedUser()) {
Ref userRef =
refs.get(RefNames.refsUsers(projectCtl.getUser().getAccountId()));
if (userRef != null) {
SymbolicRef refsUsersSelf =
new SymbolicRef(RefNames.REFS_USERS_SELF, userRef);
refs = new HashMap<>(refs);
refs.put(refsUsersSelf.getName(), refsUsersSelf);
}
}
if (projectCtl.allRefsAreVisible(ImmutableSet.of(RefNames.REFS_CONFIG))) {
Map<String, Ref> r = Maps.newHashMap(refs);
if (!projectCtl.controlForRef(RefNames.REFS_CONFIG).isVisible()) {
@@ -97,7 +110,8 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
Account.Id accountId;
if (ref.getName().startsWith(RefNames.REFS_CACHE_AUTOMERGE)) {
continue;
} else if ((accountId = Account.Id.fromRef(ref.getName())) != null) {
} else if ((accountId =
Account.Id.fromRef(ref.getLeaf().getName())) != null) {
// Reference related to an account is visible only for the current
// account.
//

View File

@@ -38,6 +38,7 @@ import com.google.gerrit.rules.RulesCache;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.CapabilityCollection;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.BranchOrderSection;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -80,6 +81,7 @@ public class ProjectState {
}
private final boolean isAllProjects;
private final boolean isAllUsers;
private final SitePaths sitePaths;
private final AllProjectsName allProjectsName;
private final ProjectCache projectCache;
@@ -113,6 +115,7 @@ public class ProjectState {
final SitePaths sitePaths,
final ProjectCache projectCache,
final AllProjectsName allProjectsName,
final AllUsersName allUsersName,
final ProjectControl.AssistedFactory projectControlFactory,
final PrologEnvironment.Factory envFactory,
final GitRepositoryManager gitMgr,
@@ -122,6 +125,7 @@ public class ProjectState {
this.sitePaths = sitePaths;
this.projectCache = projectCache;
this.isAllProjects = config.getProject().getNameKey().equals(allProjectsName);
this.isAllUsers = config.getProject().getNameKey().equals(allUsersName);
this.allProjectsName = allProjectsName;
this.projectControlFactory = projectControlFactory;
this.envFactory = envFactory;
@@ -362,6 +366,10 @@ public class ProjectState {
return isAllProjects;
}
public boolean isAllUsers() {
return isAllUsers;
}
public boolean isUseContributorAgreements() {
return getInheritableBoolean(new Function<Project, InheritableBoolean>() {
@Override

View File

@@ -51,6 +51,8 @@ import com.google.gerrit.server.account.GroupMembership;
import com.google.gerrit.server.account.ListGroupMembership;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllProjectsNameProvider;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.schema.SchemaCreator;
@@ -218,6 +220,8 @@ public class RefControlTest {
private final AllProjectsName allProjectsName =
new AllProjectsName(AllProjectsNameProvider.DEFAULT);
private final AllUsersName allUsersName =
new AllUsersName(AllUsersNameProvider.DEFAULT);
private final AccountGroup.UUID fixers = new AccountGroup.UUID("test.fixers");
private final Map<Project.NameKey, ProjectState> all = new HashMap<>();
private Project.NameKey localKey = new Project.NameKey("local");
@@ -858,9 +862,10 @@ public class RefControlTest {
} catch (IOException | ConfigInvalidException e) {
throw new RuntimeException(e);
}
all.put(pc.getName(), new ProjectState(sitePaths,
projectCache, allProjectsName, projectControlFactory, envFactory,
repoManager, rulesCache, commentLinks, pc));
all.put(pc.getName(),
new ProjectState(sitePaths, projectCache, allProjectsName, allUsersName,
projectControlFactory, envFactory, repoManager, rulesCache,
commentLinks, pc));
return repo;
}