Merge "Allow admin to create repository submit requirements"
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index dc0f346..33a3b38 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1661,6 +1661,18 @@
+
By default `false`.
+[[change.allowMarkdownBase64ImagesInComments]]change.allowMarkdownBase64ImagesInComments::
++
+Allows Base64 encoded images, embedded via Markdown, to be rendered in Gerrit comments.
++
+This feature addresses the need for teams to share images directly within Gerrit comments.
+Instead of relying on external image hosting, images are encoded into Base64 strings
+and included in the comment text using Markdown image syntax.
++
+When enabled, the Gerrit UI will detect and render these inline images.
++
+By default `false`.
+
[[change.propagateSubmitRequirementErrors]]change.propagateSubmitRequirementErrors::
+
If set, requests that access the submit requirements of a change fail with an
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index 73cd1f1..e066038 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -2051,6 +2051,8 @@
link:config-gerrit.html#change.enableRobotComments[Are robot comments enabled?].
|`conflicts_predicate_enabled`|not set if `false`|
link:config-gerrit.html#change.conflictsPredicateEnabled[Are conflicts enabled?].
+|`allow_markdown_base64_images_in_comments`|not set if `false`|
+link:config-gerrit.html#change.allowMarkdownBase64ImagesInComments[Are markdown base64 images in comments allowed?].
|=============================
[[change-index-config-info]]
diff --git a/java/com/google/gerrit/acceptance/testsuite/change/ChangeOperationsImpl.java b/java/com/google/gerrit/acceptance/testsuite/change/ChangeOperationsImpl.java
index a4f77a1..2d68974 100644
--- a/java/com/google/gerrit/acceptance/testsuite/change/ChangeOperationsImpl.java
+++ b/java/com/google/gerrit/acceptance/testsuite/change/ChangeOperationsImpl.java
@@ -471,7 +471,7 @@
private ChangeInserter getChangeInserter(Change.Id changeId, String refName, ObjectId commitId) {
ChangeInserter inserter = changeInserterFactory.create(changeId, commitId, refName);
- inserter.setMessage(String.format("Uploaded patchset %d.", inserter.getPatchSetId().get()));
+ inserter.setMessage(String.format("Uploaded patch set %d.", inserter.getPatchSetId().get()));
return inserter;
}
@@ -667,7 +667,7 @@
PatchSetInserter patchSetInserter =
patchsetInserterFactory.create(changeNotes, patchsetId, newPatchsetCommit);
patchSetInserter.setCheckAddPatchSetPermission(false);
- patchSetInserter.setMessage(String.format("Uploaded patchset %d.", patchsetId.get()));
+ patchSetInserter.setMessage(String.format("Uploaded patch set %d.", patchsetId.get()));
return patchSetInserter;
}
diff --git a/java/com/google/gerrit/extensions/common/ChangeConfigInfo.java b/java/com/google/gerrit/extensions/common/ChangeConfigInfo.java
index 80bf130..dd4549f 100644
--- a/java/com/google/gerrit/extensions/common/ChangeConfigInfo.java
+++ b/java/com/google/gerrit/extensions/common/ChangeConfigInfo.java
@@ -23,4 +23,5 @@
public String mergeabilityComputationBehavior;
public Boolean enableRobotComments;
public Boolean conflictsPredicateEnabled;
+ public Boolean allowMarkdownBase64ImagesInComments;
}
diff --git a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
index 0b254ce..df94b54 100644
--- a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
+++ b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
@@ -228,6 +228,8 @@
info.enableRobotComments = toBoolean(config.getBoolean("change", "enableRobotComments", false));
info.conflictsPredicateEnabled =
toBoolean(config.getBoolean("change", "conflictsPredicateEnabled", true));
+ info.allowMarkdownBase64ImagesInComments =
+ toBoolean(config.getBoolean("change", "allowMarkdownBase64ImagesInComments", false));
return info;
}
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index 634906e..c15b4c6 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -597,17 +597,56 @@
ChangeApi change = gApi.changes().id(project.get() + "~master~" + r.getChangeId());
CherryPickInput in = new CherryPickInput();
in.destination = "master";
- in.message = "it generates a new patch set\n\nChange-Id: " + r.getChangeId();
- ChangeInfo cherryInfo = change.revision(r.getCommit().name()).cherryPick(in).get();
+ ChangeInfo cherryInfo = change.current().cherryPick(in).get();
assertThat(cherryInfo.messages).hasSize(2);
- Iterator<ChangeMessageInfo> cherryIt = cherryInfo.messages.iterator();
+ Iterator<ChangeMessageInfo> cherryMessageIt = cherryInfo.messages.iterator();
assertThat(cherryInfo.cherryPickOfChange).isEqualTo(change.get()._number);
// Existing change was updated.
assertThat(cherryInfo._number).isEqualTo(change.get()._number);
+ assertThat(cherryInfo.cherryPickOfChange).isEqualTo(change.get()._number);
assertThat(cherryInfo.cherryPickOfPatchSet).isEqualTo(1);
- assertThat(cherryIt.next().message).isEqualTo("Uploaded patch set 1.");
- assertThat(cherryIt.next().message).isEqualTo("Patch Set 2: Cherry Picked from branch master.");
+ assertThat(cherryMessageIt.next().message).isEqualTo("Uploaded patch set 1.");
+ assertThat(cherryMessageIt.next().message)
+ .isEqualTo("Patch Set 2: Cherry Picked from branch master.");
+ }
+
+ @Test
+ public void restoreOldPatchSetByCherryPickToSameBranch() throws Exception {
+ Change.Id changeId =
+ changeOperations.newChange().project(project).file("a.txt").content("aContent").create();
+ ChangeApi change = gApi.changes().id(project.get(), changeId.get());
+
+ // Amend the change, deleting file a.txt and adding file b.txt.
+ changeOperations
+ .change(changeId)
+ .newPatchset()
+ .file("a.txt")
+ .delete()
+ .file("b.txt")
+ .content("bContent")
+ .create();
+
+ // Restore patch set 1 by cherry-picking it.
+ CherryPickInput in = new CherryPickInput();
+ in.destination = "master";
+ ChangeInfo cherryInfo = change.revision(1).cherryPick(in).get();
+ assertThat(cherryInfo.messages).hasSize(3);
+ Iterator<ChangeMessageInfo> cherryMessageIt = cherryInfo.messages.iterator();
+ assertThat(cherryInfo.cherryPickOfChange).isEqualTo(change.get()._number);
+
+ // Existing change was updated.
+ assertThat(cherryInfo._number).isEqualTo(change.get()._number);
+ assertThat(cherryInfo.cherryPickOfChange).isEqualTo(change.get()._number);
+ assertThat(cherryInfo.cherryPickOfPatchSet).isEqualTo(1);
+ assertThat(cherryMessageIt.next().message).isEqualTo("Uploaded patch set 1.");
+ assertThat(cherryMessageIt.next().message).isEqualTo("Uploaded patch set 2.");
+ assertThat(cherryMessageIt.next().message)
+ .isEqualTo("Patch Set 3: Cherry Picked from branch master.");
+
+ // File a.txt has been restored and b.txt has been removed.
+ Map<String, FileInfo> files = change.current().files();
+ assertThat(files.keySet()).containsExactly("a.txt", COMMIT_MSG);
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java b/javatests/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
index 479baf3..8fd40c3 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
@@ -73,7 +73,7 @@
@GerritConfig(name = "change.updateDelay", value = "50s")
@GerritConfig(name = "change.disablePrivateChanges", value = "true")
@GerritConfig(name = "change.enableRobotComments", value = "false")
-
+ @GerritConfig(name = "change.allowMarkdownBase64ImagesInComments", value = "false")
// download
@GerritConfig(
name = "download.archive",
@@ -114,6 +114,7 @@
assertThat(i.change.updateDelay).isEqualTo(50);
assertThat(i.change.disablePrivateChanges).isTrue();
assertThat(i.change.enableRobotComments).isNull();
+ assertThat(i.change.allowMarkdownBase64ImagesInComments).isNull();
// download
assertThat(i.download.archives).containsExactly("tar", "tbz2", "tgz", "txz");
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
index 17e24b5..66a461e 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
@@ -157,6 +157,7 @@
.weblinks.show,
.referenceContainer {
display: block;
+ align-content: center;
}
.rightsText {
margin-right: var(--spacing-s);
@@ -165,11 +166,15 @@
.editing gr-button,
.admin #editBtn {
display: inline-block;
- margin: var(--spacing-l) 0;
+ margin: var(--spacing-l);
}
.editing #editInheritFromInput {
display: inline-block;
}
+
+ .topLevelButtons {
+ display: flex;
+ }
`,
];
}
@@ -210,11 +215,40 @@
}}
></gr-autocomplete>
</h3>
- <div class="weblinks ${this.weblinks?.length ? 'show' : ''}">
- History:
- ${this.weblinks?.map(
- info => html`<gr-weblink .info=${info}></gr-weblink>`
- )}
+ <div class="topLevelButtons">
+ <div class="weblinks ${this.weblinks?.length ? 'show' : ''}">
+ History:
+ ${this.weblinks?.map(
+ info => html`<gr-weblink .info=${info}></gr-weblink>`
+ )}
+ </div>
+ <div>
+ <gr-button
+ id="editBtn"
+ @click=${() => {
+ this.handleEdit();
+ }}
+ >${this.editing ? 'Cancel' : 'Edit'}</gr-button
+ >
+ <gr-button
+ id="saveBtn"
+ class=${this.ownerOf && this.ownerOf.length === 0
+ ? 'invisible'
+ : ''}
+ primary
+ ?disabled=${!this.modified || this.disableSaveWithoutReview}
+ @click=${this.handleSave}
+ >Save</gr-button
+ >
+ <gr-button
+ id="saveReviewBtn"
+ class=${!this.canUpload ? 'invisible' : ''}
+ primary
+ ?disabled=${!this.modified}
+ @click=${this.handleSaveForReview}
+ >Save For Review</gr-button
+ >
+ </div>
</div>
${this.sections?.map((section, index) =>
this.renderPermissionSections(section, index)
@@ -226,33 +260,6 @@
>Add Reference</gr-button
>
</div>
- <div>
- <gr-button
- id="editBtn"
- @click=${() => {
- this.handleEdit();
- }}
- >${this.editing ? 'Cancel' : 'Edit'}</gr-button
- >
- <gr-button
- id="saveBtn"
- class=${this.ownerOf && this.ownerOf.length === 0
- ? 'invisible'
- : ''}
- primary
- ?disabled=${!this.modified || this.disableSaveWithoutReview}
- @click=${this.handleSave}
- >Save</gr-button
- >
- <gr-button
- id="saveReviewBtn"
- class=${!this.canUpload ? 'invisible' : ''}
- primary
- ?disabled=${!this.modified}
- @click=${this.handleSaveForReview}
- >Save For Review</gr-button
- >
- </div>
</div>
</div>
`;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.ts
index d5eb17a..6437e9f 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.ts
@@ -137,7 +137,40 @@
<a href="" id="inheritFromName" rel="noopener"> </a>
<gr-autocomplete id="editInheritFromInput"> </gr-autocomplete>
</h3>
- <div class="weblinks">History:</div>
+ <div class="topLevelButtons">
+ <div class="weblinks">History:</div>
+ <div>
+ <gr-button
+ aria-disabled="false"
+ id="editBtn"
+ role="button"
+ tabindex="0"
+ >
+ Edit
+ </gr-button>
+ <gr-button
+ aria-disabled="true"
+ disabled=""
+ class="invisible"
+ id="saveBtn"
+ primary=""
+ role="button"
+ tabindex="-1"
+ >
+ Save
+ </gr-button>
+ <gr-button
+ aria-disabled="false"
+ class="invisible"
+ id="saveReviewBtn"
+ primary=""
+ role="button"
+ tabindex="0"
+ >
+ Save For Review
+ </gr-button>
+ </div>
+ </div>
<div class="referenceContainer">
<gr-button
aria-disabled="false"
@@ -148,37 +181,6 @@
Add Reference
</gr-button>
</div>
- <div>
- <gr-button
- aria-disabled="false"
- id="editBtn"
- role="button"
- tabindex="0"
- >
- Edit
- </gr-button>
- <gr-button
- aria-disabled="true"
- disabled=""
- class="invisible"
- id="saveBtn"
- primary=""
- role="button"
- tabindex="-1"
- >
- Save
- </gr-button>
- <gr-button
- aria-disabled="false"
- class="invisible"
- id="saveReviewBtn"
- primary=""
- role="button"
- tabindex="0"
- >
- Save For Review
- </gr-button>
- </div>
</div>
</div>
`
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
index 13c5d36..12e9a43 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
@@ -1780,7 +1780,7 @@
'/edit:publish',
assertUIActionInfo(this.actions.publishEdit),
false,
- {notify: NotifyType.NONE}
+ {notify: NotifyType.OWNER_REVIEWERS}
);
this.sendPublishEditEvent();
}
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
index d68cdbf..662c560 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
@@ -212,6 +212,9 @@
@state()
shouldRender = false;
+ @state()
+ runs: CheckRun[] = [];
+
private readonly reporting = getAppContext().reportingService;
private getChecksModel = resolve(this, checksModelToken);
@@ -223,6 +226,13 @@
() => this.getChecksModel().checksSelectedAttemptNumber$,
x => (this.selectedAttempt = x)
);
+ subscribe(
+ this,
+ () => this.getChecksModel().allRunsSelectedPatchset$,
+ x => {
+ this.runs = x;
+ }
+ );
}
override firstUpdated() {
@@ -296,6 +306,18 @@
attempt !== ALL_ATTEMPTS;
const selected = this.selectedAttempt === attempt;
return html`<div class="attemptDetail">
+ ${when(
+ typeof attempt === 'number',
+ () => html` <gr-hovercard-run
+ .run=${this.runs.find(
+ r =>
+ r.attempt === attempt &&
+ r.checkName === this.run?.checkName &&
+ r.pluginName === this.run?.pluginName
+ )}
+ .attempt=${attempt}
+ ></gr-hovercard-run>`
+ )}
<input
type="radio"
id=${id}
diff --git a/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts b/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts
index cc3ce77..b38a30e 100644
--- a/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts
+++ b/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts
@@ -20,6 +20,7 @@
import {HovercardMixin} from '../../mixins/hovercard-mixin/hovercard-mixin';
import {css, html, LitElement} from 'lit';
import {checksStyles} from './gr-checks-styles';
+import {when} from 'lit/directives/when.js';
// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
const base = HovercardMixin(LitElement);
@@ -29,6 +30,9 @@
@property({type: Object})
run?: RunResult | CheckRun;
+ @property({type: Number})
+ attempt?: number;
+
static override get styles() {
return [
fontStyles,
@@ -146,6 +150,7 @@
<div class="sectionContent">
<h3 class="name heading-3">
<span>${this.run.checkName}</span>
+ ${when(this.attempt, () => html`(Attempt ${this.attempt})`)}
</h3>
</div>
</div>
@@ -196,6 +201,8 @@
}
private renderAttemptSection() {
+ // If an attempt is specified, we don't need to render the attempt section.
+ if (this.attempt) return;
if (this.hideAttempts()) return;
const attempts = this.computeAttempts();
return html`
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
index 7f35f04..5731522 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
@@ -510,7 +510,7 @@
HttpMethod.POST,
'/edit:publish',
undefined,
- {notify: NotifyType.NONE},
+ {notify: NotifyType.OWNER_REVIEWERS},
handleError
)
.then(res => {
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
index c445817..fa2a4ff 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
@@ -131,31 +131,6 @@
link: '$1',
enabled: true,
};
-
- // Linkify schemeless URLs with proper domain structures.
- this.repoCommentLinks['ALWAYS_LINK_SCHEMELESS'] = {
- // (?<=\s|^|[('":[]) // Ensure the match is preceded by whitespace,
- // // start of line, or one of ( ' " : [
- // ( // Start capture group 1
- // (?: // Start non-capturing domain group
- // [\w-]+\. // Sequence of words/hyphens with dot, e.g. "a-b."
- // )+ // End domain group. Require at least one match
- // [\w-]+ // End with words/hyphens for TLD e.g. "com"
- // (?: // Start optional non-capturing path/query/fragment group
- // [/?#] // Start with one of / ? #
- // [^\s'"]* // Followed by some chars that are not whitespace,
- // // ' or " (to not grab trailing quotes)
- // )? // End optional path/query/fragment group
- // ) // End capture group 1
- // (?=\s|$|[)'"!?.,]) // Ensure the match is followed by whitespace,
- // // end of line, or one of ) ' " ! ? . ,
- match:
- '(?<=\\s|^|[(\'":[])((?:[\\w-]+\\.)+[\\w-]+(?:[/?#][^\\s\'"]*)?)(?=\\s|$|[)\'"!?.,])',
- // Prepend http:// for the link href otherwise it will be treated as
- // a relative URL.
- link: 'http://$1',
- enabled: true,
- };
}
);
}
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
index 38606c7..723267e 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
@@ -240,18 +240,7 @@
element.content = url;
await element.updateComplete;
const a = queryAndAssert<HTMLElement>(element, 'a');
-
- // URLs without scheme are upgraded to https:// by the
- // ALWAYS_LINK_SCHEMELESS rule. URLs with http:// or https://
- // are preserved by the ALWAYS_LINK_HTTP rule.
- const isSchemeless =
- !url.startsWith('http://') &&
- !url.startsWith('https://') &&
- !url.startsWith('mailto:') &&
- !url.startsWith('/');
- const expectedHref = isSchemeless ? `http://${url}` : url;
-
- assert.equal(a.getAttribute('href'), expectedHref);
+ assert.equal(a.getAttribute('href'), url);
assert.equal(a.innerText, url);
};
@@ -265,14 +254,6 @@
await checkLinking(
'https://google.com/traces/list?project=gerrit&tid=123'
);
-
- await checkLinking('www.google.com');
- await checkLinking('www.google.com/path');
- await checkLinking('google.com');
- await checkLinking('sub.google.co.uk');
- await checkLinking('google-foo.com');
- await checkLinking('google.io');
- await checkLinking('google.com?q=1#frag');
});
});
@@ -767,18 +748,7 @@
await element.updateComplete;
const a = queryAndAssert<HTMLElement>(element, 'a');
const p = queryAndAssert<HTMLElement>(element, 'p');
-
- // URLs without scheme are upgraded to https:// by the
- // ALWAYS_LINK_SCHEMELESS rule. URLs with http:// or https://
- // are preserved by the ALWAYS_LINK_HTTP rule.
- const isSchemeless =
- !url.startsWith('http://') &&
- !url.startsWith('https://') &&
- !url.startsWith('mailto:') &&
- !url.startsWith('/');
- const expectedHref = isSchemeless ? `http://${url}` : url;
-
- assert.equal(a.getAttribute('href'), expectedHref);
+ assert.equal(a.getAttribute('href'), url);
assert.equal(p.innerText, url);
};
@@ -789,14 +759,6 @@
await checkLinking(
'https://google.com/traces/list?project=gerrit&tid=123'
);
-
- await checkLinking('www.google.com');
- await checkLinking('www.google.com/path');
- await checkLinking('google.com');
- await checkLinking('sub.google.co.uk');
- await checkLinking('google-foo.com');
- await checkLinking('google.io');
- await checkLinking('google.com?q=1#frag');
});
suite('user suggest fix', () => {
diff --git a/polygerrit-ui/app/utils/label-util_test.ts b/polygerrit-ui/app/utils/label-util_test.ts
index a0b6c50..4e29079 100644
--- a/polygerrit-ui/app/utils/label-util_test.ts
+++ b/polygerrit-ui/app/utils/label-util_test.ts
@@ -27,6 +27,8 @@
hasVotes,
hasVoted,
extractLabelsWithCountFrom,
+ orderSubmitRequirements,
+ StandardLabels,
} from './label-util';
import {
AccountId,
@@ -901,4 +903,57 @@
assert.isTrue(hasVoted(quickLabelInfo, account));
});
});
+
+ suite('orderSubmitRequirements', () => {
+ test('orders priority requirements first', () => {
+ const codeReview = {
+ ...createSubmitRequirementResultInfo(),
+ name: StandardLabels.CODE_REVIEW,
+ };
+ const codeOwners = {
+ ...createSubmitRequirementResultInfo(),
+ name: StandardLabels.CODE_OWNERS,
+ };
+ const presubmitVerified = {
+ ...createSubmitRequirementResultInfo(),
+ name: StandardLabels.PRESUBMIT_VERIFIED,
+ };
+ const customLabel = createSubmitRequirementResultInfo('Custom-Label');
+
+ const requirements = [
+ customLabel,
+ codeReview,
+ presubmitVerified,
+ codeOwners,
+ ];
+ const ordered = orderSubmitRequirements(requirements);
+
+ assert.deepEqual(ordered, [
+ codeReview,
+ codeOwners,
+ presubmitVerified,
+ customLabel,
+ ]);
+ });
+
+ test('preserves order of non-priority requirements', () => {
+ const customLabel1 = {
+ ...createSubmitRequirementResultInfo(),
+ name: 'Custom-Label-1',
+ };
+ const customLabel2 = {
+ ...createSubmitRequirementResultInfo(),
+ name: 'Custom-Label-2',
+ };
+ const customLabel3 = {
+ ...createSubmitRequirementResultInfo(),
+ name: 'Custom-Label-3',
+ };
+
+ const requirements = [customLabel2, customLabel1, customLabel3];
+ const ordered = orderSubmitRequirements(requirements);
+
+ assert.deepEqual(ordered, requirements);
+ });
+ });
});