Merge branch 'stable-3.0'

* stable-3.0:
  Fix single tab indentation in diff
  Add plugin-manager as core plugin
  Set version to 3.0.0-rc2
  Update highlight.js to master branch
  Stop using deprecated SoyListData and SoyMapData
  PolyGerrit: Fix typos in comments
  gr-create-project-dialog: Fix typo in element id name
  AccountIT: Fix typo in variable name
  Set version to 2.16.9-SNAPSHOT
  AccountIT: Add tests for email notification on adding SSH/GPG keys
  AccountApi: Add methods to generate and set the HTTP password

Change-Id: Ic9f174c5fbe38fa9e4de2bed58e541d94f1df9bd
This commit is contained in:
David Pursehouse
2019-05-03 18:12:47 +09:00
18 changed files with 300 additions and 136 deletions

1
.gitignore vendored
View File

@@ -41,6 +41,7 @@
!/plugins/external_plugin_deps.bzl !/plugins/external_plugin_deps.bzl
!/plugins/gitiles !/plugins/gitiles
!/plugins/hooks !/plugins/hooks
!/plugins/plugin-manager
!/plugins/replication !/plugins/replication
!/plugins/reviewnotes !/plugins/reviewnotes
!/plugins/singleusergroup !/plugins/singleusergroup

5
.gitmodules vendored
View File

@@ -28,6 +28,11 @@
url = ../plugins/hooks url = ../plugins/hooks
branch = . branch = .
[submodule "plugins/plugin-manager"]
path = plugins/plugin-manager
url = ../plugins/plugin-manager
branch = .
[submodule "plugins/replication"] [submodule "plugins/replication"]
path = plugins/replication path = plugins/replication
url = ../plugins/replication url = ../plugins/replication

View File

@@ -110,6 +110,20 @@ Documentation] |
link:https://gerrit.googlesource.com/plugins/hooks/+doc/master/src/main/resources/Documentation/config.md[ link:https://gerrit.googlesource.com/plugins/hooks/+doc/master/src/main/resources/Documentation/config.md[
Configuration] Configuration]
[[plugin-manager]]
=== plugin-manager
This plugins provides an initial wizard to discover and install Gerrit plugins.
Per default GerritForge CI is used to download the plugin artifacts from, but
this can be changed per plugin configuration.
link:https://gerrit-review.googlesource.com/admin/repos/plugins/plugin-manager[
Project]
link:https://gerrit.googlesource.com/plugins/plugin-manager/+doc/master/src/main/resources/Documentation/about.md[
Documentation]
link:https://gerrit.googlesource.com/plugins/plugin-manager/+doc/master/src/main/resources/Documentation/config.md[
Configuration]
[[replication]] [[replication]]
=== replication === replication

View File

@@ -114,6 +114,23 @@ public interface AccountApi {
void setName(String name) throws RestApiException; void setName(String name) throws RestApiException;
/**
* Generate a new HTTP password.
*
* @return the generated password.
*/
String generateHttpPassword() throws RestApiException;
/**
* Set a new HTTP password.
*
* <p>May only be invoked by administrators.
*
* @param httpPassword the new password, {@code null} to remove the password.
* @return the new password, {@code null} if the password was removed.
*/
String setHttpPassword(String httpPassword) throws RestApiException;
/** /**
* A default implementation which allows source compatibility when adding new methods to the * A default implementation which allows source compatibility when adding new methods to the
* interface. * interface.
@@ -317,5 +334,15 @@ public interface AccountApi {
public void setName(String name) throws RestApiException { public void setName(String name) throws RestApiException {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@Override
public String generateHttpPassword() throws RestApiException {
throw new NotImplementedException();
}
@Override
public String setHttpPassword(String httpPassword) throws RestApiException {
throw new NotImplementedException();
}
} }
} }

View File

@@ -22,13 +22,14 @@ import com.google.common.io.Resources;
import com.google.gerrit.common.Nullable; import com.google.gerrit.common.Nullable;
import com.google.template.soy.SoyFileSet; import com.google.template.soy.SoyFileSet;
import com.google.template.soy.data.SanitizedContent; import com.google.template.soy.data.SanitizedContent;
import com.google.template.soy.data.SoyMapData;
import com.google.template.soy.data.UnsafeSanitizedContentOrdainer; import com.google.template.soy.data.UnsafeSanitizedContentOrdainer;
import com.google.template.soy.tofu.SoyTofu; import com.google.template.soy.tofu.SoyTofu;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@@ -74,8 +75,8 @@ public class IndexServlet extends HttpServlet {
return uri.getPath().replaceAll("/$", ""); return uri.getPath().replaceAll("/$", "");
} }
static SoyMapData getTemplateData(String canonicalURL, String cdnPath, String faviconPath) static Map<String, String> getTemplateData(
throws URISyntaxException { String canonicalURL, String cdnPath, String faviconPath) throws URISyntaxException {
String canonicalPath = computeCanonicalPath(canonicalURL); String canonicalPath = computeCanonicalPath(canonicalURL);
String staticPath = ""; String staticPath = "";
@@ -91,9 +92,10 @@ public class IndexServlet extends HttpServlet {
UnsafeSanitizedContentOrdainer.ordainAsSafe( UnsafeSanitizedContentOrdainer.ordainAsSafe(
staticPath, SanitizedContent.ContentKind.TRUSTED_RESOURCE_URI); staticPath, SanitizedContent.ContentKind.TRUSTED_RESOURCE_URI);
return new SoyMapData( Map<String, String> data = new HashMap<>();
"canonicalPath", canonicalPath, data.put("canonicalPath", canonicalPath);
"staticResourcePath", sanitizedStaticPath, data.put("staticResourcePath", sanitizedStaticPath.coerceToString());
"faviconPath", faviconPath); data.put("faviconPath", faviconPath);
return data;
} }
} }

View File

@@ -40,6 +40,7 @@ import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.EmailInfo; import com.google.gerrit.extensions.common.EmailInfo;
import com.google.gerrit.extensions.common.GpgKeyInfo; import com.google.gerrit.extensions.common.GpgKeyInfo;
import com.google.gerrit.extensions.common.GroupInfo; import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.common.HttpPasswordInput;
import com.google.gerrit.extensions.common.Input; import com.google.gerrit.extensions.common.Input;
import com.google.gerrit.extensions.common.NameInput; import com.google.gerrit.extensions.common.NameInput;
import com.google.gerrit.extensions.common.SshKeyInfo; import com.google.gerrit.extensions.common.SshKeyInfo;
@@ -75,6 +76,7 @@ import com.google.gerrit.server.restapi.account.Index;
import com.google.gerrit.server.restapi.account.PostWatchedProjects; import com.google.gerrit.server.restapi.account.PostWatchedProjects;
import com.google.gerrit.server.restapi.account.PutActive; import com.google.gerrit.server.restapi.account.PutActive;
import com.google.gerrit.server.restapi.account.PutAgreement; import com.google.gerrit.server.restapi.account.PutAgreement;
import com.google.gerrit.server.restapi.account.PutHttpPassword;
import com.google.gerrit.server.restapi.account.PutName; import com.google.gerrit.server.restapi.account.PutName;
import com.google.gerrit.server.restapi.account.PutStatus; import com.google.gerrit.server.restapi.account.PutStatus;
import com.google.gerrit.server.restapi.account.SetDiffPreferences; import com.google.gerrit.server.restapi.account.SetDiffPreferences;
@@ -135,6 +137,7 @@ public class AccountApiImpl implements AccountApi {
private final GetGroups getGroups; private final GetGroups getGroups;
private final EmailApiImpl.Factory emailApi; private final EmailApiImpl.Factory emailApi;
private final PutName putName; private final PutName putName;
private final PutHttpPassword putHttpPassword;
@Inject @Inject
AccountApiImpl( AccountApiImpl(
@@ -177,6 +180,7 @@ public class AccountApiImpl implements AccountApi {
GetGroups getGroups, GetGroups getGroups,
EmailApiImpl.Factory emailApi, EmailApiImpl.Factory emailApi,
PutName putName, PutName putName,
PutHttpPassword putPassword,
@Assisted AccountResource account) { @Assisted AccountResource account) {
this.account = account; this.account = account;
this.accountLoaderFactory = ailf; this.accountLoaderFactory = ailf;
@@ -218,6 +222,7 @@ public class AccountApiImpl implements AccountApi {
this.getGroups = getGroups; this.getGroups = getGroups;
this.emailApi = emailApi; this.emailApi = emailApi;
this.putName = putName; this.putName = putName;
this.putHttpPassword = putPassword;
} }
@Override @Override
@@ -593,4 +598,31 @@ public class AccountApiImpl implements AccountApi {
throw asRestApiException("Cannot set account name", e); throw asRestApiException("Cannot set account name", e);
} }
} }
@Override
public String generateHttpPassword() throws RestApiException {
HttpPasswordInput input = new HttpPasswordInput();
input.generate = true;
try {
// Response should never be 'none' for a generated password, but
// let's make sure.
Response<String> result = putHttpPassword.apply(account, input);
return result.isNone() ? null : result.value();
} catch (Exception e) {
throw asRestApiException("Cannot generate HTTP password", e);
}
}
@Override
public String setHttpPassword(String password) throws RestApiException {
HttpPasswordInput input = new HttpPasswordInput();
input.generate = false;
input.httpPassword = password;
try {
Response<String> result = putHttpPassword.apply(account, input);
return result.isNone() ? null : result.value();
} catch (Exception e) {
throw asRestApiException("Cannot generate HTTP password", e);
}
}
} }

View File

@@ -44,15 +44,15 @@ import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackendException; import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.project.ProjectState; import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.server.query.change.ChangeData;
import com.google.template.soy.data.SoyListData;
import com.google.template.soy.data.SoyMapData;
import java.io.IOException; import java.io.IOException;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
@@ -560,11 +560,11 @@ public abstract class ChangeEmail extends NotificationEmail {
* a 'type' key which maps to one of 'common', 'add' or 'remove' and a 'text' key which maps to * a 'type' key which maps to one of 'common', 'add' or 'remove' and a 'text' key which maps to
* the line's content. * the line's content.
*/ */
private SoyListData getDiffTemplateData() { private List<Map<String, String>> getDiffTemplateData() {
SoyListData result = new SoyListData(); List<Map<String, String>> result = new ArrayList<>();
Splitter lineSplitter = Splitter.on(System.getProperty("line.separator")); Splitter lineSplitter = Splitter.on(System.getProperty("line.separator"));
for (String diffLine : lineSplitter.split(getUnifiedDiff())) { for (String diffLine : lineSplitter.split(getUnifiedDiff())) {
SoyMapData lineData = new SoyMapData(); Map<String, String> lineData = new HashMap<>();
lineData.put("text", diffLine); lineData.put("text", diffLine);
// Skip empty lines and lines that look like diff headers. // Skip empty lines and lines that look like diff headers.

View File

@@ -1890,8 +1890,11 @@ public class AccountIT extends AbstractDaemonTest {
String id = key.getKeyIdString(); String id = key.getKeyIdString();
addExternalIdEmail(admin, "test1@example.com"); addExternalIdEmail(admin, "test1@example.com");
sender.clear();
assertKeyMapContains(key, addGpgKey(key.getPublicKeyArmored())); assertKeyMapContains(key, addGpgKey(key.getPublicKeyArmored()));
assertKeys(key); assertKeys(key);
assertThat(sender.getMessages()).hasSize(1);
assertThat(sender.getMessages().get(0).body()).contains("new GPG keys have been added");
requestScopeOperations.setApiUser(user.id()); requestScopeOperations.setApiUser(user.id());
exception.expect(ResourceNotFoundException.class); exception.expect(ResourceNotFoundException.class);
@@ -1906,14 +1909,21 @@ public class AccountIT extends AbstractDaemonTest {
String id = key.getKeyIdString(); String id = key.getKeyIdString();
PGPPublicKey pk = key.getPublicKey(); PGPPublicKey pk = key.getPublicKey();
sender.clear();
GpgKeyInfo info = addGpgKey(armor(pk)).get(id); GpgKeyInfo info = addGpgKey(armor(pk)).get(id);
assertThat(info.userIds).hasSize(2); assertThat(info.userIds).hasSize(2);
assertIteratorSize(2, getOnlyKeyFromStore(key).getUserIDs()); assertIteratorSize(2, getOnlyKeyFromStore(key).getUserIDs());
assertThat(sender.getMessages()).hasSize(1);
assertThat(sender.getMessages().get(0).body()).contains("new GPG keys have been added");
pk = PGPPublicKey.removeCertification(pk, "foo:myId"); pk = PGPPublicKey.removeCertification(pk, "foo:myId");
sender.clear();
info = addGpgKeyNoReindex(armor(pk)).get(id); info = addGpgKeyNoReindex(armor(pk)).get(id);
assertThat(info.userIds).hasSize(1); assertThat(info.userIds).hasSize(1);
assertIteratorSize(1, getOnlyKeyFromStore(key).getUserIDs()); assertIteratorSize(1, getOnlyKeyFromStore(key).getUserIDs());
// TODO: Issue 10769: Adding an already existing key should not result in a notification email
assertThat(sender.getMessages()).hasSize(1);
assertThat(sender.getMessages().get(0).body()).contains("new GPG keys have been added");
} }
@Test @Test
@@ -2023,32 +2033,42 @@ public class AccountIT extends AbstractDaemonTest {
assertSequenceNumbers(info); assertSequenceNumbers(info);
SshKeyInfo key = info.get(0); SshKeyInfo key = info.get(0);
KeyPair keyPair = sshKeys.getKeyPair(admin); KeyPair keyPair = sshKeys.getKeyPair(admin);
String inital = TestSshKeys.publicKey(keyPair, admin.email()); String initial = TestSshKeys.publicKey(keyPair, admin.email());
assertThat(key.sshPublicKey).isEqualTo(inital); assertThat(key.sshPublicKey).isEqualTo(initial);
accountIndexedCounter.assertNoReindex(); accountIndexedCounter.assertNoReindex();
// Add a new key // Add a new key
sender.clear();
String newKey = TestSshKeys.publicKey(TestSshKeys.genSshKey(), admin.email()); String newKey = TestSshKeys.publicKey(TestSshKeys.genSshKey(), admin.email());
gApi.accounts().self().addSshKey(newKey); gApi.accounts().self().addSshKey(newKey);
info = gApi.accounts().self().listSshKeys(); info = gApi.accounts().self().listSshKeys();
assertThat(info).hasSize(2); assertThat(info).hasSize(2);
assertSequenceNumbers(info); assertSequenceNumbers(info);
accountIndexedCounter.assertReindexOf(admin); accountIndexedCounter.assertReindexOf(admin);
assertThat(sender.getMessages()).hasSize(1);
assertThat(sender.getMessages().get(0).body()).contains("new SSH keys have been added");
// Add an existing key (the request succeeds, but the key isn't added again) // Add an existing key (the request succeeds, but the key isn't added again)
gApi.accounts().self().addSshKey(inital); sender.clear();
gApi.accounts().self().addSshKey(initial);
info = gApi.accounts().self().listSshKeys(); info = gApi.accounts().self().listSshKeys();
assertThat(info).hasSize(2); assertThat(info).hasSize(2);
assertSequenceNumbers(info); assertSequenceNumbers(info);
accountIndexedCounter.assertNoReindex(); accountIndexedCounter.assertNoReindex();
// TODO: Issue 10769: Adding an already existing key should not result in a notification email
assertThat(sender.getMessages()).hasSize(1);
assertThat(sender.getMessages().get(0).body()).contains("new SSH keys have been added");
// Add another new key // Add another new key
sender.clear();
String newKey2 = TestSshKeys.publicKey(TestSshKeys.genSshKey(), admin.email()); String newKey2 = TestSshKeys.publicKey(TestSshKeys.genSshKey(), admin.email());
gApi.accounts().self().addSshKey(newKey2); gApi.accounts().self().addSshKey(newKey2);
info = gApi.accounts().self().listSshKeys(); info = gApi.accounts().self().listSshKeys();
assertThat(info).hasSize(3); assertThat(info).hasSize(3);
assertSequenceNumbers(info); assertSequenceNumbers(info);
accountIndexedCounter.assertReindexOf(admin); accountIndexedCounter.assertReindexOf(admin);
assertThat(sender.getMessages()).hasSize(1);
assertThat(sender.getMessages().get(0).body()).contains("new SSH keys have been added");
// Delete second key // Delete second key
gApi.accounts().self().deleteSshKey(2); gApi.accounts().self().deleteSshKey(2);
@@ -2718,6 +2738,67 @@ public class AccountIT extends AbstractDaemonTest {
} }
} }
@Test
public void userCanGenerateNewHttpPassword() throws Exception {
String newPassword = gApi.accounts().self().generateHttpPassword();
assertThat(newPassword).isNotNull();
}
@Test
public void adminCanGenerateNewHttpPasswordForUser() throws Exception {
requestScopeOperations.setApiUser(admin.id());
String newPassword = gApi.accounts().id(user.username()).generateHttpPassword();
assertThat(newPassword).isNotNull();
}
@Test
public void userCannotGenerateNewHttpPasswordForOtherUser() throws Exception {
requestScopeOperations.setApiUser(user.id());
exception.expect(AuthException.class);
gApi.accounts().id(admin.username()).generateHttpPassword();
}
@Test
public void userCannotExplicitlySetHttpPassword() throws Exception {
requestScopeOperations.setApiUser(user.id());
exception.expect(AuthException.class);
gApi.accounts().self().setHttpPassword("my-new-password");
}
@Test
public void userCannotExplicitlySetHttpPasswordForOtherUser() throws Exception {
requestScopeOperations.setApiUser(user.id());
exception.expect(AuthException.class);
gApi.accounts().id(admin.username()).setHttpPassword("my-new-password");
}
@Test
public void userCanRemoveHttpPassword() throws Exception {
requestScopeOperations.setApiUser(user.id());
assertThat(gApi.accounts().self().setHttpPassword(null)).isNull();
}
@Test
public void userCannotRemoveHttpPasswordForOtherUser() throws Exception {
requestScopeOperations.setApiUser(user.id());
exception.expect(AuthException.class);
gApi.accounts().id(admin.username()).setHttpPassword(null);
}
@Test
public void adminCanExplicitlySetHttpPasswordForUser() throws Exception {
requestScopeOperations.setApiUser(admin.id());
String httpPassword = "new-password-for-user";
assertThat(gApi.accounts().id(user.username()).setHttpPassword(httpPassword))
.isEqualTo(httpPassword);
}
@Test
public void adminCanRemoveHttpPasswordForUser() throws Exception {
requestScopeOperations.setApiUser(admin.id());
assertThat(gApi.accounts().id(user.username()).setHttpPassword(null)).isNull();
}
private void createDraft(PushOneCommit.Result r, String path, String message) throws Exception { private void createDraft(PushOneCommit.Result r, String path, String message) throws Exception {
DraftInput in = new DraftInput(); DraftInput in = new DraftInput();
in.path = path; in.path = path;

View File

@@ -18,8 +18,8 @@ import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.gerrit.testing.GerritBaseTests; import com.google.gerrit.testing.GerritBaseTests;
import com.google.template.soy.data.SoyMapData;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.Map;
import org.junit.Test; import org.junit.Test;
public class IndexServletTest extends GerritBaseTests { public class IndexServletTest extends GerritBaseTests {
@@ -38,35 +38,34 @@ public class IndexServletTest extends GerritBaseTests {
@Test @Test
public void noPathAndNoCDN() throws URISyntaxException { public void noPathAndNoCDN() throws URISyntaxException {
SoyMapData data = IndexServlet.getTemplateData("http://example.com/", null, null); Map<String, String> data = IndexServlet.getTemplateData("http://example.com/", null, null);
assertThat(data.getSingle("canonicalPath").stringValue()).isEqualTo(""); assertThat(data.get("canonicalPath")).isEqualTo("");
assertThat(data.getSingle("staticResourcePath").stringValue()).isEqualTo(""); assertThat(data.get("staticResourcePath")).isEqualTo("");
} }
@Test @Test
public void pathAndNoCDN() throws URISyntaxException { public void pathAndNoCDN() throws URISyntaxException {
SoyMapData data = IndexServlet.getTemplateData("http://example.com/gerrit/", null, null); Map<String, String> data =
assertThat(data.getSingle("canonicalPath").stringValue()).isEqualTo("/gerrit"); IndexServlet.getTemplateData("http://example.com/gerrit/", null, null);
assertThat(data.getSingle("staticResourcePath").stringValue()).isEqualTo("/gerrit"); assertThat(data.get("canonicalPath")).isEqualTo("/gerrit");
assertThat(data.get("staticResourcePath")).isEqualTo("/gerrit");
} }
@Test @Test
public void noPathAndCDN() throws URISyntaxException { public void noPathAndCDN() throws URISyntaxException {
SoyMapData data = Map<String, String> data =
IndexServlet.getTemplateData("http://example.com/", "http://my-cdn.com/foo/bar/", null); IndexServlet.getTemplateData("http://example.com/", "http://my-cdn.com/foo/bar/", null);
assertThat(data.getSingle("canonicalPath").stringValue()).isEqualTo(""); assertThat(data.get("canonicalPath")).isEqualTo("");
assertThat(data.getSingle("staticResourcePath").stringValue()) assertThat(data.get("staticResourcePath")).isEqualTo("http://my-cdn.com/foo/bar/");
.isEqualTo("http://my-cdn.com/foo/bar/");
} }
@Test @Test
public void pathAndCDN() throws URISyntaxException { public void pathAndCDN() throws URISyntaxException {
SoyMapData data = Map<String, String> data =
IndexServlet.getTemplateData( IndexServlet.getTemplateData(
"http://example.com/gerrit", "http://my-cdn.com/foo/bar/", null); "http://example.com/gerrit", "http://my-cdn.com/foo/bar/", null);
assertThat(data.getSingle("canonicalPath").stringValue()).isEqualTo("/gerrit"); assertThat(data.get("canonicalPath")).isEqualTo("/gerrit");
assertThat(data.getSingle("staticResourcePath").stringValue()) assertThat(data.get("staticResourcePath")).isEqualTo("http://my-cdn.com/foo/bar/");
.isEqualTo("http://my-cdn.com/foo/bar/");
} }
@Test @Test

File diff suppressed because one or more lines are too long

View File

@@ -85,7 +85,7 @@ limitations under the License.
<span class="title">Create initial empty commit</span> <span class="title">Create initial empty commit</span>
<span class="value"> <span class="value">
<gr-select <gr-select
id="initalCommit" id="initialCommit"
bind-value="{{_repoConfig.create_empty_commit}}"> bind-value="{{_repoConfig.create_empty_commit}}">
<select> <select>
<option value="false">False</option> <option value="false">False</option>

View File

@@ -50,7 +50,7 @@ limitations under the License.
}); });
test('default values are populated', () => { test('default values are populated', () => {
assert.isTrue(element.$.initalCommit.bindValue); assert.isTrue(element.$.initialCommit.bindValue);
assert.isFalse(element.$.parentRepo.bindValue); assert.isFalse(element.$.parentRepo.bindValue);
}); });
@@ -83,7 +83,7 @@ limitations under the License.
element.$.repoNameInput.bindValue = configInputObj.name; element.$.repoNameInput.bindValue = configInputObj.name;
element.$.rightsInheritFromInput.bindValue = configInputObj.parent; element.$.rightsInheritFromInput.bindValue = configInputObj.parent;
element.$.ownerInput.text = configInputObj.owners[0]; element.$.ownerInput.text = configInputObj.owners[0];
element.$.initalCommit.bindValue = element.$.initialCommit.bindValue =
configInputObj.create_empty_commit; configInputObj.create_empty_commit;
element.$.parentRepo.bindValue = element.$.parentRepo.bindValue =
configInputObj.permissions_only; configInputObj.permissions_only;

View File

@@ -98,7 +98,7 @@ limitations under the License.
loadCommentSpy = sandbox.spy(commentApiWrapper.$.commentAPI, 'loadAll'); loadCommentSpy = sandbox.spy(commentApiWrapper.$.commentAPI, 'loadAll');
// Stub methods on the changeComments object after changeComments has // Stub methods on the changeComments object after changeComments has
// been initalized. // been initialized.
commentApiWrapper.loadComments().then(() => { commentApiWrapper.loadComments().then(() => {
sandbox.stub(element.changeComments, 'getPaths').returns({}); sandbox.stub(element.changeComments, 'getPaths').returns({});
sandbox.stub(element.changeComments, 'getCommentsBySideForPath') sandbox.stub(element.changeComments, 'getCommentsBySideForPath')
@@ -1451,7 +1451,7 @@ limitations under the License.
sandbox.stub(element, '_reviewFile'); sandbox.stub(element, '_reviewFile');
// Stub methods on the changeComments object after changeComments has // Stub methods on the changeComments object after changeComments has
// been initalized. // been initialized.
commentApiWrapper.loadComments().then(() => { commentApiWrapper.loadComments().then(() => {
sandbox.stub(element.changeComments, 'getPaths').returns({}); sandbox.stub(element.changeComments, 'getPaths').returns({});
sandbox.stub(element.changeComments, 'getCommentsBySideForPath') sandbox.stub(element.changeComments, 'getCommentsBySideForPath')

View File

@@ -149,7 +149,7 @@ limitations under the License.
element.messages = messages; element.messages = messages;
// Stub methods on the changeComments object after changeComments has // Stub methods on the changeComments object after changeComments has
// been initalized. // been initialized.
return commentApiWrapper.loadComments(); return commentApiWrapper.loadComments();
}); });
@@ -466,7 +466,7 @@ limitations under the License.
element.messages = messages; element.messages = messages;
// Stub methods on the changeComments object after changeComments has // Stub methods on the changeComments object after changeComments has
// been initalized. // been initialized.
return commentApiWrapper.loadComments(); return commentApiWrapper.loadComments();
}); });

View File

@@ -183,6 +183,7 @@ limitations under the License.
color: var(--diff-tab-indicator-color); color: var(--diff-tab-indicator-color);
/* >> character */ /* >> character */
content: '\00BB'; content: '\00BB';
position: absolute;
} }
/* Is defined after other background-colors, such that this /* Is defined after other background-colors, such that this
rule wins in case of same specificity. */ rule wins in case of same specificity. */

View File

@@ -76,7 +76,7 @@ limitations under the License.
element = commentApiWrapper.$.patchRange; element = commentApiWrapper.$.patchRange;
// Stub methods on the changeComments object after changeComments has // Stub methods on the changeComments object after changeComments has
// been initalized. // been initialized.
return commentApiWrapper.loadComments(); return commentApiWrapper.loadComments();
}); });

View File

@@ -5,6 +5,7 @@ CORE_PLUGINS = [
"download-commands", "download-commands",
"gitiles", "gitiles",
"hooks", "hooks",
"plugin-manager",
"replication", "replication",
"reviewnotes", "reviewnotes",
"singleusergroup", "singleusergroup",