Merge "Improve Documentation for User Suggested Edits"
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 8aa5c7f..eb6080f 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -7374,9 +7374,10 @@
|`message` ||
The text left by the user or Gerrit system. Accounts are served as account IDs
inlined in the text as `<GERRIT_ACCOUNT_18419>`.
-All accounts, used in message, can be found in `accountsInMessage`
+All accounts, used in message, can be found in `accounts_in_message`
field.
-|`accountsInMessage` ||Accounts, used in `message`.
+|`accounts_in_message` ||
+link:rest-api-accounts.html#account-info[AccountInfo] list, used in `message`.
|`tag` |optional|
Value of the `tag` field from link:#review-input[ReviewInput] set
while posting the review. Votes/comments that contain `tag` with
diff --git a/java/com/google/gerrit/server/project/SubmitRequirementsEvaluatorImpl.java b/java/com/google/gerrit/server/project/SubmitRequirementsEvaluatorImpl.java
index 0991f20..39e12c4 100644
--- a/java/com/google/gerrit/server/project/SubmitRequirementsEvaluatorImpl.java
+++ b/java/com/google/gerrit/server/project/SubmitRequirementsEvaluatorImpl.java
@@ -77,7 +77,9 @@
@Override
public void validateExpression(SubmitRequirementExpression expression)
throws QueryParseException {
- queryBuilder.get().parse(expression.expressionString());
+ try (ManualRequestContext ignored = requestContext.open()) {
+ queryBuilder.get().parse(expression.expressionString());
+ }
}
@Override
diff --git a/javatests/com/google/gerrit/acceptance/server/project/SubmitRequirementsValidationIT.java b/javatests/com/google/gerrit/acceptance/server/project/SubmitRequirementsValidationIT.java
index a643d56..63068c6 100644
--- a/javatests/com/google/gerrit/acceptance/server/project/SubmitRequirementsValidationIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/project/SubmitRequirementsValidationIT.java
@@ -19,13 +19,32 @@
import static com.google.gerrit.acceptance.GitUtil.fetch;
import static com.google.gerrit.acceptance.GitUtil.pushHead;
+import com.google.common.collect.ImmutableList;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.entities.RefNames;
+import com.google.gerrit.extensions.annotations.Exports;
+import com.google.gerrit.extensions.client.ListChangesOption;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.SubmitRequirementResultInfo;
+import com.google.gerrit.index.query.Matchable;
+import com.google.gerrit.index.query.OperatorPredicate;
+import com.google.gerrit.index.query.Predicate;
+import com.google.gerrit.index.query.QueryParseException;
+import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.project.ProjectConfig;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gerrit.server.query.change.ChangeQueryBuilder;
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.util.List;
import java.util.Locale;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.transport.PushResult;
@@ -447,6 +466,98 @@
r.assertOkStatus();
}
+ protected static class IsOperatorModule extends AbstractModule {
+ @Override
+ public void configure() {
+ bind(ChangeQueryBuilder.ChangeIsOperandFactory.class)
+ .annotatedWith(Exports.named("changeNumberEven"))
+ .to(SampleIsOperand.class);
+ }
+ }
+
+ private static class SampleIsOperand implements ChangeQueryBuilder.ChangeIsOperandFactory {
+ final Provider<CurrentUser> currentUserProvider;
+
+ @Inject
+ SampleIsOperand(Provider<CurrentUser> currentUserProvider) {
+ this.currentUserProvider = currentUserProvider;
+ }
+
+ @Override
+ public Predicate<ChangeData> create(ChangeQueryBuilder builder) throws QueryParseException {
+ return new IsSamplePredicate(currentUserProvider.get());
+ }
+ }
+
+ private static class IsSamplePredicate extends OperatorPredicate<ChangeData>
+ implements Matchable<ChangeData> {
+
+ CurrentUser currentUser;
+
+ public IsSamplePredicate(CurrentUser currentUser) {
+ super("is", "changeNumberEven");
+ this.currentUser = currentUser;
+ assertServerUser();
+ }
+
+ private void assertServerUser() {
+ try {
+ currentUser.asIdentifiedUser();
+ throw new IllegalStateException("is an identified user");
+ } catch (UnsupportedOperationException e) {
+ // as expected.
+ }
+ }
+
+ @Override
+ public boolean match(ChangeData changeData) {
+ assertServerUser();
+ return true;
+ }
+
+ @Override
+ public int getCost() {
+ return 0;
+ }
+ }
+
+ @Test
+ public void submitRequirementValidationRunsAsServer() throws Exception {
+ try (TestRepository<Repository> testRepo =
+ new TestRepository<>(repoManager.openRepository(project))) {
+ testRepo.delete(RefNames.REFS_CONFIG);
+ }
+
+ PushOneCommit.Result r = createChange();
+ String changeId = r.getChangeId();
+
+ try (AutoCloseable ignored = installPlugin("myplugin", IsOperatorModule.class)) {
+ PushOneCommit push =
+ pushFactory
+ .create(
+ admin.newIdent(),
+ testRepo,
+ "Test Change",
+ ProjectConfig.PROJECT_CONFIG,
+ "[submit-requirement \"SAMPLE\"]\n"
+ + " submittableIf = is:changeNumberEven_myplugin\n")
+ .setParents(ImmutableList.of());
+ PushOneCommit.Result cfgPush = push.to(RefNames.REFS_CONFIG);
+ cfgPush.assertOkStatus();
+
+ ChangeInfo info = gApi.changes().id(changeId).get(ListChangesOption.SUBMIT_REQUIREMENTS);
+ List<SubmitRequirementResultInfo> results =
+ info.submitRequirements.stream()
+ .filter(x -> x.name.equals("SAMPLE"))
+ .collect(Collectors.toList());
+ assertThat(results).hasSize(1);
+ assertThat(results.get(0).status).isNotEqualTo(SubmitRequirementResultInfo.Status.ERROR);
+ }
+
+ // TODO(hanwen): should return 500 ISE for
+ // gApi.changes().id(changeId).get(ListChangesOption.SUBMIT_REQUIREMENTS);
+ }
+
@Test
public void invalidSubmitRequirementIsRejectedWhenPushingForReview() throws Exception {
fetchRefsMetaConfig();
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
index 1a70f2b..ca7a78f 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
@@ -112,12 +112,15 @@
</section>
<section>
<span class="title">Default Branch</span>
- <iron-input
- .bindValue=${convertToString(this.defaultBranch)}
- @bind-value-changed=${this.handleBranchNameBindValueChanged}
- >
- <input id="defaultBranchNameInput" autocomplete="off" />
- </iron-input>
+ <span class="value">
+ <gr-autocomplete
+ id="defaultBranchNameInput"
+ .text=${convertToString(this.defaultBranch)}
+ .placeholder=${"Optional, defaults to 'master'"}
+ @text-changed=${this.handleBranchNameBindValueChanged}
+ >
+ </gr-autocomplete>
+ </span>
</section>
<section>
<span class="title">Rights inherit from</span>
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.ts b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.ts
index 63b8c06..f8476e6 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.ts
@@ -39,9 +39,9 @@
</section>
<section>
<span class="title"> Default Branch </span>
- <iron-input>
- <input autocomplete="off" id="defaultBranchNameInput" />
- </iron-input>
+ <span class="value">
+ <gr-autocomplete id="defaultBranchNameInput"> </gr-autocomplete>
+ </span>
</section>
<section>
<span class="title"> Rights inherit from </span>
diff --git a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
index 640b9d0..29a22a3 100644
--- a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
+++ b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
@@ -42,7 +42,6 @@
import {submitRequirementsStyles} from '../../../styles/gr-submit-requirements-styles';
import {resolve} from '../../../models/dependency';
import {checksModelToken} from '../../../models/checks/checks-model';
-import {join} from 'lit/directives/join.js';
import {map} from 'lit/directives/map.js';
/**
@@ -111,14 +110,15 @@
white-space: nowrap;
vertical-align: top;
}
- .votes-cell {
+ .votes {
+ display: flex;
+ flex-flow: column;
+ row-gap: var(--spacing-s);
+ }
+ .votes-line {
display: flex;
flex-flow: wrap;
}
- .votes-cell .separator {
- width: 100%;
- margin-top: var(--spacing-s);
- }
gr-vote-chip {
margin-right: var(--spacing-s);
}
@@ -280,16 +280,21 @@
hasVotes(allLabels[label])
);
- return html`${join(
- map(
+ return html`<div class="votes">
+ ${map(
associatedLabelsWithVotes,
label =>
- html`${this.renderLabelVote(label, allLabels)}
- ${this.renderOverrideLabels(requirement, label)}`
- ),
- html`<span class="separator"></span>`
- )}
- ${this.renderChecks(requirement)}`;
+ html`<div class="votes-line">
+ ${this.renderLabelVote(label, allLabels)}
+ ${this.renderOverrideLabels(
+ requirement,
+ label,
+ associatedLabelsWithVotes.length > 1
+ )}
+ ${this.renderChecks(requirement, label)}
+ </div>`
+ )}
+ </div> `;
}
renderLabelVote(label: string, labels: LabelNameToInfoMap) {
@@ -317,12 +322,17 @@
renderOverrideLabels(
requirement: SubmitRequirementResultInfo,
- forLabel: string
+ forLabel: string,
+ showForAllLabel: boolean
) {
- if (requirement.status !== SubmitRequirementStatus.OVERRIDDEN) return;
+ if (
+ !showForAllLabel &&
+ requirement.status !== SubmitRequirementStatus.OVERRIDDEN
+ )
+ return;
const requirementLabels = extractAssociatedLabels(
requirement,
- 'onlyOverride'
+ showForAllLabel ? 'all' : 'onlyOverride'
)
.filter(label => label === forLabel)
.filter(label => {
@@ -334,13 +344,17 @@
);
}
- renderChecks(requirement: SubmitRequirementResultInfo) {
+ renderChecks(requirement: SubmitRequirementResultInfo, labelName?: string) {
const requirementLabels = extractAssociatedLabels(requirement);
const errorRuns = this.runs
.filter(run => hasResultsOf(run, Category.ERROR))
- .filter(
- run => run.labelName && requirementLabels.includes(run.labelName)
- );
+ .filter(run => {
+ if (labelName) {
+ return labelName === run.labelName;
+ } else {
+ return run.labelName && requirementLabels.includes(run.labelName);
+ }
+ });
const errorRunsCount = errorRuns.reduce(
(sum, run) => sum + getResultsOf(run, Category.ERROR).length,
0
@@ -357,9 +371,13 @@
.filter(
r => r.status === RunStatus.RUNNING || r.status === RunStatus.SCHEDULED
)
- .filter(
- run => run.labelName && requirementLabels.includes(run.labelName)
- );
+ .filter(run => {
+ if (labelName) {
+ return labelName === run.labelName;
+ } else {
+ return run.labelName && requirementLabels.includes(run.labelName);
+ }
+ });
const runningRunsCount = runningRuns.length;
if (runningRunsCount > 0) {
diff --git a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements_test.ts b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements_test.ts
index 212394c..a5a336c 100644
--- a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements_test.ts
@@ -102,7 +102,11 @@
>
<gr-endpoint-param name="change"></gr-endpoint-param>
<gr-endpoint-param name="requirement"></gr-endpoint-param>
- <gr-vote-chip></gr-vote-chip>
+ <div class="votes">
+ <div class="votes-line">
+ <gr-vote-chip> </gr-vote-chip>
+ </div>
+ </div>
</gr-endpoint-decorator>
</td>
</tr>
@@ -125,7 +129,11 @@
votesCell?.[0],
/* HTML */ `
<div class="votes-cell">
- <gr-vote-chip> </gr-vote-chip>
+ <div class="votes">
+ <div class="votes-line">
+ <gr-vote-chip> </gr-vote-chip>
+ </div>
+ </div>
</div>
`
);
@@ -174,8 +182,12 @@
votesCell?.[0],
/* HTML */ `
<div class="votes-cell">
- <gr-vote-chip></gr-vote-chip>
- <gr-checks-chip></gr-checks-chip>
+ <div class="votes">
+ <div class="votes-line">
+ <gr-vote-chip> </gr-vote-chip>
+ <gr-checks-chip> </gr-checks-chip>
+ </div>
+ </div>
</div>
`
);
@@ -196,8 +208,12 @@
votesCell?.[0],
/* HTML */ `
<div class="votes-cell">
- <gr-vote-chip></gr-vote-chip>
- <gr-checks-chip></gr-checks-chip>
+ <div class="votes">
+ <div class="votes-line">
+ <gr-vote-chip> </gr-vote-chip>
+ <gr-checks-chip> </gr-checks-chip>
+ </div>
+ </div>
</div>
`
);
@@ -231,8 +247,12 @@
assert.dom.equal(
votesCell?.[0],
/* HTML */ `<div class="votes-cell">
- <gr-vote-chip> </gr-vote-chip>
- <span class="overrideLabel"> Override </span>
+ <div class="votes">
+ <div class="votes-line">
+ <gr-vote-chip> </gr-vote-chip>
+ <span class="overrideLabel"> Override </span>
+ </div>
+ </div>
</div>`
);
});
@@ -274,11 +294,16 @@
assert.dom.equal(
votesCell?.[0],
/* HTML */ `<div class="votes-cell">
- <gr-vote-chip> </gr-vote-chip>
- <span class="overrideLabel"> Override </span>
- <span class="separator"></span>
- <gr-vote-chip> </gr-vote-chip>
- <span class="overrideLabel"> Override2 </span>
+ <div class="votes">
+ <div class="votes-line">
+ <gr-vote-chip> </gr-vote-chip>
+ <span class="overrideLabel"> Override </span>
+ </div>
+ <div class="votes-line">
+ <gr-vote-chip> </gr-vote-chip>
+ <span class="overrideLabel"> Override2 </span>
+ </div>
+ </div>
</div>`
);
});
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.ts b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.ts
index 681378d..1cda32b 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.ts
@@ -70,6 +70,9 @@
var(--tooltip-background-color);
top: calc(-1 * var(--gr-tooltip-arrow-size));
}
+ .text {
+ white-space: pre;
+ }
`,
];
}
@@ -82,7 +85,7 @@
class="arrowPositionBelow arrow"
style=${styleMap({marginLeft: this.arrowCenterOffset})}
></i>
- ${this.text}
+ <div class="text">${this.text}</div>
<i
class="arrowPositionAbove arrow"
style=${styleMap({marginLeft: this.arrowCenterOffset})}
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.ts b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.ts
index 63ed1ff..bc0cfba 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.ts
@@ -26,7 +26,7 @@
/* HTML */ `
<div class="tooltip">
<i class="arrow arrowPositionBelow" style="margin-left:0;"> </i>
- tooltipText
+ <div class="text">tooltipText</div>
<i class="arrow arrowPositionAbove" style="margin-left:0;"> </i>
</div>
`